LCOV - code coverage report
Current view: top level - source/renderer/backend/gl - Texture.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 1 159 0.6 %
Date: 2023-01-19 00:18:29 Functions: 2 9 22.2 %

          Line data    Source code
       1             : /* Copyright (C) 2022 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "Texture.h"
      21             : 
      22             : #include "lib/code_annotation.h"
      23             : #include "lib/config2.h"
      24             : #include "renderer/backend/gl/Device.h"
      25             : #include "renderer/backend/gl/DeviceCommandContext.h"
      26             : #include "renderer/backend/gl/Mapping.h"
      27             : 
      28             : #include <algorithm>
      29             : 
      30             : namespace Renderer
      31             : {
      32             : 
      33             : namespace Backend
      34             : {
      35             : 
      36             : namespace GL
      37             : {
      38             : 
      39             : namespace
      40             : {
      41             : 
      42           0 : GLint CalculateMinFilter(const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount)
      43             : {
      44           0 :     if (MIPLevelCount == 1)
      45           0 :         return defaultSamplerDesc.minFilter == Sampler::Filter::LINEAR ? GL_LINEAR : GL_NEAREST;
      46             : 
      47           0 :     if (defaultSamplerDesc.minFilter == Sampler::Filter::LINEAR)
      48           0 :         return defaultSamplerDesc.mipFilter == Sampler::Filter::LINEAR ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR_MIPMAP_NEAREST;
      49             : 
      50           0 :     return defaultSamplerDesc.mipFilter == Sampler::Filter::LINEAR ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST;
      51             : }
      52             : 
      53           0 : GLint AddressModeToGLEnum(Sampler::AddressMode addressMode)
      54             : {
      55           0 :     switch (addressMode)
      56             :     {
      57           0 :     case Sampler::AddressMode::REPEAT: return GL_REPEAT;
      58           0 :     case Sampler::AddressMode::MIRRORED_REPEAT: return GL_MIRRORED_REPEAT;
      59           0 :     case Sampler::AddressMode::CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE;
      60           0 :     case Sampler::AddressMode::CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER;
      61             :     }
      62           0 :     return GL_REPEAT;
      63             : }
      64             : 
      65           0 : GLenum TypeToGLEnum(CTexture::Type type)
      66             : {
      67           0 :     GLenum target = GL_TEXTURE_2D;
      68           0 :     switch (type)
      69             :     {
      70           0 :     case CTexture::Type::TEXTURE_2D:
      71           0 :         target = GL_TEXTURE_2D;
      72           0 :         break;
      73           0 :     case CTexture::Type::TEXTURE_2D_MULTISAMPLE:
      74             : #if CONFIG2_GLES
      75             :         ENSURE(false && "Multisample textures are unsupported on GLES");
      76             : #else
      77           0 :         target = GL_TEXTURE_2D_MULTISAMPLE;
      78             : #endif
      79           0 :         break;
      80           0 :     case CTexture::Type::TEXTURE_CUBE:
      81           0 :         target = GL_TEXTURE_CUBE_MAP;
      82           0 :         break;
      83             :     }
      84           0 :     return target;
      85             : }
      86             : 
      87             : } // anonymous namespace
      88             : 
      89             : // static
      90           0 : std::unique_ptr<CTexture> CTexture::Create(
      91             :     CDevice* device, const char* name, const Type type, const uint32_t usage,
      92             :     const Format format, const uint32_t width, const uint32_t height,
      93             :     const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
      94             : {
      95           0 :     std::unique_ptr<CTexture> texture(new CTexture());
      96             : 
      97           0 :     ENSURE(format != Format::UNDEFINED);
      98           0 :     ENSURE(width > 0 && height > 0 && MIPLevelCount > 0);
      99           0 :     ENSURE((type == Type::TEXTURE_2D_MULTISAMPLE && sampleCount > 1 && !(usage & ITexture::Usage::SAMPLED)) || sampleCount == 1);
     100             : 
     101           0 :     texture->m_Device = device;
     102           0 :     texture->m_Type = type;
     103           0 :     texture->m_Usage = usage;
     104           0 :     texture->m_Format = format;
     105           0 :     texture->m_Width = width;
     106           0 :     texture->m_Height = height;
     107           0 :     texture->m_MIPLevelCount = MIPLevelCount;
     108             : 
     109           0 :     glGenTextures(1, &texture->m_Handle);
     110             : 
     111           0 :     ogl_WarnIfError();
     112             : 
     113           0 :     const GLenum target = TypeToGLEnum(type);
     114             : 
     115             :     CDeviceCommandContext::ScopedBind scopedBind(
     116           0 :         texture->m_Device->GetActiveCommandContext(), target, texture->m_Handle);
     117             : 
     118             :     // It's forbidden to set sampler state for multisample textures.
     119           0 :     if (type != Type::TEXTURE_2D_MULTISAMPLE)
     120             :     {
     121           0 :         glTexParameteri(target, GL_TEXTURE_MIN_FILTER, CalculateMinFilter(defaultSamplerDesc, MIPLevelCount));
     122           0 :         glTexParameteri(target, GL_TEXTURE_MAG_FILTER, defaultSamplerDesc.magFilter == Sampler::Filter::LINEAR ? GL_LINEAR : GL_NEAREST);
     123             : 
     124           0 :         ogl_WarnIfError();
     125             : 
     126           0 :         glTexParameteri(target, GL_TEXTURE_WRAP_S, AddressModeToGLEnum(defaultSamplerDesc.addressModeU));
     127           0 :         glTexParameteri(target, GL_TEXTURE_WRAP_T, AddressModeToGLEnum(defaultSamplerDesc.addressModeV));
     128             :     }
     129             : 
     130             : #if !CONFIG2_GLES
     131           0 :     if (type == Type::TEXTURE_CUBE)
     132           0 :         glTexParameteri(target, GL_TEXTURE_WRAP_R, AddressModeToGLEnum(defaultSamplerDesc.addressModeW));
     133             : #endif
     134             : 
     135           0 :     ogl_WarnIfError();
     136             : 
     137             : #if !CONFIG2_GLES
     138           0 :     glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
     139           0 :     glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, MIPLevelCount - 1);
     140             : 
     141           0 :     if (defaultSamplerDesc.mipLODBias != 0.0f)
     142           0 :         glTexParameteri(target, GL_TEXTURE_LOD_BIAS, defaultSamplerDesc.mipLODBias);
     143             : #endif // !CONFIG2_GLES
     144             : 
     145           0 :     if (type == Type::TEXTURE_2D && defaultSamplerDesc.anisotropyEnabled)
     146             :     {
     147           0 :         ENSURE(texture->m_Device->GetCapabilities().anisotropicFiltering);
     148             :         const float maxAnisotropy = std::min(
     149           0 :             defaultSamplerDesc.maxAnisotropy, texture->m_Device->GetCapabilities().maxAnisotropy);
     150           0 :         glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnisotropy);
     151             :     }
     152             : 
     153           0 :     if (defaultSamplerDesc.addressModeU == Sampler::AddressMode::CLAMP_TO_BORDER ||
     154           0 :         defaultSamplerDesc.addressModeV == Sampler::AddressMode::CLAMP_TO_BORDER ||
     155           0 :         defaultSamplerDesc.addressModeW == Sampler::AddressMode::CLAMP_TO_BORDER)
     156             :     {
     157           0 :         CColor borderColor(0.0f, 0.0f, 0.0f, 0.0f);
     158           0 :         switch (defaultSamplerDesc.borderColor)
     159             :         {
     160           0 :         case Sampler::BorderColor::TRANSPARENT_BLACK:
     161           0 :             break;
     162           0 :         case Sampler::BorderColor::OPAQUE_BLACK:
     163           0 :             borderColor = CColor(0.0f, 0.0f, 0.0f, 1.0f);
     164           0 :             break;
     165           0 :         case Sampler::BorderColor::OPAQUE_WHITE:
     166           0 :             borderColor = CColor(1.0f, 1.0f, 1.0f, 1.0f);
     167           0 :             break;
     168             :         }
     169           0 :         glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, borderColor.AsFloatArray().data());
     170             :     }
     171             : 
     172           0 :     ogl_WarnIfError();
     173             : 
     174           0 :     if (type == CTexture::Type::TEXTURE_2D)
     175             :     {
     176           0 :         bool compressedFormat = false;
     177           0 :         GLint internalFormat = GL_RGBA;
     178             :         // Actually pixel data is nullptr so it doesn't make sense to account
     179             :         // it, but in theory some buggy drivers might complain about invalid
     180             :         // pixel format.
     181           0 :         GLenum pixelFormat = GL_RGBA;
     182           0 :         GLenum pixelType = GL_UNSIGNED_BYTE;
     183           0 :         switch (format)
     184             :         {
     185           0 :         case Format::UNDEFINED:
     186           0 :             debug_warn("Texture should defined format");
     187           0 :             break;
     188           0 :         case Format::R8G8B8A8_UNORM:
     189           0 :             break;
     190           0 :         case Format::R8G8B8_UNORM:
     191           0 :             internalFormat = GL_RGB;
     192           0 :             pixelFormat = GL_RGB;
     193           0 :             pixelType = GL_UNSIGNED_BYTE;
     194           0 :             break;
     195             : #if !CONFIG2_GLES
     196           0 :         case Format::R8_UNORM:
     197           0 :             internalFormat = GL_RED;
     198           0 :             pixelFormat = GL_RED;
     199           0 :             pixelType = GL_UNSIGNED_BYTE;
     200           0 :             break;
     201             : #endif
     202           0 :         case Format::A8_UNORM:
     203           0 :             internalFormat = GL_ALPHA;
     204           0 :             pixelFormat = GL_ALPHA;
     205           0 :             pixelType = GL_UNSIGNED_BYTE;
     206           0 :             break;
     207           0 :         case Format::L8_UNORM:
     208           0 :             internalFormat = GL_LUMINANCE;
     209           0 :             pixelFormat = GL_LUMINANCE;
     210           0 :             pixelType = GL_UNSIGNED_BYTE;
     211           0 :             break;
     212             : #if CONFIG2_GLES
     213             :         // GLES requires pixel type == UNSIGNED_SHORT or UNSIGNED_INT for depth.
     214             :         case Format::D16_UNORM: FALLTHROUGH;
     215             :         case Format::D24_UNORM: FALLTHROUGH;
     216             :         case Format::D32_SFLOAT:
     217             :             internalFormat = GL_DEPTH_COMPONENT;
     218             :             pixelFormat = GL_DEPTH_COMPONENT;
     219             :             pixelType = GL_UNSIGNED_SHORT;
     220             :             break;
     221             :         case Format::D24_UNORM_S8_UINT:
     222             :             debug_warn("Unsupported format");
     223             :             break;
     224             : #else
     225           0 :         case Format::D16_UNORM:
     226           0 :             internalFormat = GL_DEPTH_COMPONENT16;
     227           0 :             pixelFormat = GL_DEPTH_COMPONENT;
     228           0 :             pixelType = GL_UNSIGNED_SHORT;
     229           0 :             break;
     230           0 :         case Format::D24_UNORM:
     231           0 :             internalFormat = GL_DEPTH_COMPONENT24;
     232           0 :             pixelFormat = GL_DEPTH_COMPONENT;
     233           0 :             pixelType = GL_UNSIGNED_SHORT;
     234           0 :             break;
     235           0 :         case Format::D32_SFLOAT:
     236           0 :             internalFormat = GL_DEPTH_COMPONENT32;
     237           0 :             pixelFormat = GL_DEPTH_COMPONENT;
     238           0 :             pixelType = GL_UNSIGNED_SHORT;
     239           0 :             break;
     240           0 :         case Format::D24_UNORM_S8_UINT:
     241           0 :             internalFormat = GL_DEPTH24_STENCIL8_EXT;
     242           0 :             pixelFormat = GL_DEPTH_STENCIL_EXT;
     243           0 :             pixelType = GL_UNSIGNED_INT_24_8_EXT;
     244           0 :             break;
     245             : #endif
     246           0 :         case Format::BC1_RGB_UNORM: FALLTHROUGH;
     247             :         case Format::BC1_RGBA_UNORM: FALLTHROUGH;
     248             :         case Format::BC2_UNORM: FALLTHROUGH;
     249             :         case Format::BC3_UNORM:
     250           0 :             compressedFormat = true;
     251           0 :             break;
     252           0 :         default:
     253           0 :             debug_warn("Unsupported format.");
     254             :         }
     255             :         // glCompressedTexImage2D can't accept a null data, so we will initialize it during uploading.
     256           0 :         if (!compressedFormat)
     257             :         {
     258           0 :             for (uint32_t level = 0; level < MIPLevelCount; ++level)
     259             :             {
     260           0 :                 glTexImage2D(target, level, internalFormat,
     261           0 :                     std::max(1u, width >> level), std::max(1u, height >> level),
     262             :                     0, pixelFormat, pixelType, nullptr);
     263             :             }
     264             :         }
     265             :     }
     266           0 :     else if (type == CTexture::Type::TEXTURE_2D_MULTISAMPLE)
     267             :     {
     268           0 :         ENSURE(MIPLevelCount == 1);
     269             : #if !CONFIG2_GLES
     270           0 :         if (format == Format::R8G8B8A8_UNORM)
     271             :         {
     272           0 :             glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCount, GL_RGBA8, width, height, GL_TRUE);
     273             :         }
     274           0 :         else if (format == Format::D24_UNORM_S8_UINT)
     275             :         {
     276           0 :             glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCount, GL_DEPTH24_STENCIL8_EXT, width, height, GL_TRUE);
     277             :         }
     278             :         else
     279             : #endif // !CONFIG2_GLES
     280             :         {
     281           0 :             debug_warn("Unsupported format");
     282             :         }
     283             :     }
     284             : 
     285             : 
     286             : #if !CONFIG2_GLES
     287           0 :     if (IsDepthFormat(format))
     288             :     {
     289           0 :         if (defaultSamplerDesc.compareEnabled)
     290             :         {
     291           0 :             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
     292           0 :             glTexParameteri(
     293             :                 GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC,
     294           0 :                 Mapping::FromCompareOp(defaultSamplerDesc.compareOp));
     295             :         }
     296             :         else
     297           0 :             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
     298             :     }
     299             : #endif
     300             : 
     301           0 :     ogl_WarnIfError();
     302             : 
     303           0 :     if (texture->m_Device->GetCapabilities().debugLabels)
     304             :     {
     305           0 :         glObjectLabel(GL_TEXTURE, texture->m_Handle, -1, name);
     306             :     }
     307             : 
     308           0 :     return texture;
     309             : }
     310             : 
     311             : CTexture::CTexture() = default;
     312             : 
     313           0 : CTexture::~CTexture()
     314             : {
     315           0 :     m_Device->GetActiveCommandContext()->OnTextureDestroy(this);
     316           0 :     if (m_Handle)
     317           0 :         glDeleteTextures(1, &m_Handle);
     318           0 : }
     319             : 
     320           0 : IDevice* CTexture::GetDevice()
     321             : {
     322           0 :     return m_Device;
     323             : }
     324             : 
     325             : } // namespace GL
     326             : 
     327             : } // namespace Backend
     328             : 
     329           3 : } // namespace Renderer

Generated by: LCOV version 1.13