1#include "TexturesGL20.h"
3#include "GraphicsDeviceGL20.h"
4#include "FormatsGL20.h"
6#include "Foundation/Logging/Logger.h"
16Cogs::TexturesGL20::~TexturesGL20()
18 if (this->textures.size()) {
19 LOG_WARNING(logger,
"Texture resources not empty. %zu resources left.", this->textures.size());
23void Cogs::TexturesGL20::initialize(GraphicsDeviceGL20 * device)
25 CapabilitiesGL20* capabilities = device->getCapabilities();
27 useTextureStorage = glTexStorage2D ? true :
false;
28 useAnisotropic = capabilities->EXT_texture_filter_anisotropic ? true :
false;
30 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
35 if ((desc.target != ResourceDimensions::Texture2DMS) && (desc.target != ResourceDimensions::Texture2DMSArray) && (desc.samples > 1)) {
36 LOG_ERROR(logger,
"Cannot create a non-multisampled texture with more than one sample.");
41 const GLenum target = OpenGL20::TextureTarget[(int)desc.target];
42 const GLenum textureFormat = OpenGL20::TextureFormats[(
int)desc.format];
43 const GLenum pixelType = OpenGL20::PixelTypes[(int)desc.format];
48 texture.type = target;
49 texture.textureId = GL_INVALID_VALUE;
50 texture.width = desc.width;
51 texture.height = desc.height;
52 texture.numSamples = desc.samples;
53 texture.arraySize = desc.layers;
54 texture.format = desc.format;
55 texture.flags = desc.flags;
56 texture.hasMipmaps = generateMips || desc.levels > 1;
57 GLboolean isCompressed = OpenGL20::CompressedFormats[(int)desc.format];
60 texture.textureId =
static_cast<GLuint
>(data->externalHandle);
61 return this->textures.addResource(std::move(texture));
63 glGenTextures(1, &texture.textureId);
64 glBindTexture(target, texture.textureId);
68 const GLuint textureLevels = generateMips ? 1 +
static_cast<GLuint
>(std::floor(std::log((
double)std::max(desc.width, desc.height)) / std::log(2.0))) :
static_cast<GLuint
>(desc.levels);
70 if (useTextureStorage) {
73 glTexStorage1D(target, textureLevels, textureFormat, desc.width);
75 case GL_TEXTURE_1D_ARRAY:
76 glTexStorage2D(target, textureLevels, textureFormat, desc.width, desc.layers);
79 glTexStorage2D(target, textureLevels, textureFormat, desc.width, desc.height);
81 case GL_TEXTURE_2D_ARRAY:
82 glTexStorage3D(target, textureLevels, textureFormat, desc.width, desc.height, desc.layers);
85 case GL_TEXTURE_2D_MULTISAMPLE:
86 glTexStorage2DMultisample(target, desc.samples, textureFormat, desc.width, desc.height, GLboolean(GL_TRUE));
88 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
89 glTexStorage3DMultisample(target, desc.samples, textureFormat, desc.width, desc.height, desc.layers, GLboolean(GL_TRUE));
93 glTexStorage3D(target, textureLevels, textureFormat, desc.width, desc.height, desc.depth);
95 case GL_TEXTURE_CUBE_MAP:
97 for (
unsigned f = 0; f < 6; f++) {
98 glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, 0, textureFormat, desc.width, desc.height, 0, GLsizei(data->getLevelSize(0)), data ? data->getData(0, f, 0) :
nullptr);
102 glTexStorage2D(target, textureLevels, textureFormat, desc.width, desc.height);
105 case GL_TEXTURE_CUBE_MAP_ARRAY:
106 glTexStorage3D(target, textureLevels, textureFormat, desc.width, desc.height, desc.layers * 6);
108 case GL_INVALID_ENUM:
119 if (texture.hasMipmaps && isCompressed && data) {
120 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, GLint(data->levels - 1));
124#if defined(OSOMP_EnableProfiler)
125 OsoMPAttribute profilerAttributes[7] = {
126 { COGSMEM_WidthAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.width) },
127 { COGSMEM_HeightAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.height) },
128 { COGSMEM_DepthAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.depth) },
129 { COGSMEM_LayersAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.layers) },
130 { COGSMEM_FacesAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.faces) },
131 { COGSMEM_LevelsAttribute, ATTRIBUTETYPE_Integer32,
static_cast<int32_t
>(desc.levels) },
132 { COGSMEM_FormatAttribute, ATTRIBUTETYPE_String },
135 profilerAttributes[6].mData.mText = getFormatInfo(desc.format)->
name;
136 RegisterGPUResource(glTextureFakeAddress(texture.textureId), desc.estimateMemorySize(), MemBlockType::GPUTexture, profilerAttributes, 7);
139 glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
140 if (!texture.hasMipmaps) {
143 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
146 if(data) uploadTextureData(texture, *data, 0, 0, 0);
148 glBindTexture(target, 0);
150 return this->textures.addResource(std::move(texture));
155 TextureGL20 & texture = this->textures[textureHandle];
157#if defined(OSOMP_EnableProfiler)
158 UnregisterGPUResource(glTextureFakeAddress(texture.textureId));
161 glDeleteTextures(1, &texture.textureId);
162 this->textures.removeResource(textureHandle);
165void Cogs::TexturesGL20::uploadTextureData(
TextureGL20 &texture,
167 uint32_t layer_offset,
168 uint32_t face_offset,
169 uint32_t level_offset)
171 assert(face_offset == 0 &&
"face_offset not handled");
172 assert(level_offset == 0 &&
"level_offset not handled");
174 const bool isCompressed = OpenGL20::CompressedFormats[(int)texture.format];
175 const GLenum target = texture.type;
176 const GLenum textureFormat = OpenGL20::TextureFormats[(
int)texture.format];
177 const GLenum pixelType = OpenGL20::PixelTypes[(int)texture.format];
178 const GLenum pixelFormat = OpenGL20::PixelFormats[(
int)texture.format];
185 case GL_TEXTURE_1D_ARRAY:
189 for (
size_t j = 0; j < data.levels; ++j) {
191 glCompressedTexSubImage2D(target,
static_cast<GLint
>(j), 0, 0, ext.width, ext.height, textureFormat,
static_cast<GLsizei
>(data.getLevelSize(j)), data.getData(0, 0, j));
194 case GL_TEXTURE_2D_ARRAY:
197 case GL_TEXTURE_2D_MULTISAMPLE:
200 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
206 case GL_TEXTURE_CUBE_MAP:
207 for (
size_t j = 0; j < data.levels; ++j) {
208 for (GLint c = 0; c < 6; ++c) {
210 glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + c,
static_cast<GLint
>(j), textureFormat, ext.width, ext.height, 0, GLsizei(data.getLevelSize(j)), data.getData(0, c, j));
214 case GL_TEXTURE_CUBE_MAP_ARRAY:
217 case GL_INVALID_ENUM:
224 for (
size_t j = 0; j < data.levels; ++j) {
226 glTexSubImage1D(target,
static_cast<GLint
>(j), 0, ext.width, pixelFormat, pixelType, data.getData(0, 0, j));
229 case GL_TEXTURE_1D_ARRAY:
230 for (
size_t i = 0; i < data.layers; ++i) {
231 for (
size_t j = 0; j < data.levels; ++j) {
233 glTexSubImage2D(target,
static_cast<GLint
>(j), 0,
static_cast<GLint
>(layer_offset+i), ext.width, 1, pixelFormat, pixelType, data.getData(i, 0, j));
238 for (
size_t j = 0; j < data.levels; ++j) {
240 glTexSubImage2D(target,
static_cast<GLint
>(j), 0, 0, ext.width, ext.height, pixelFormat, pixelType, data.getData(0, 0, j));
243 case GL_TEXTURE_2D_ARRAY:
244 for (
size_t i = 0; i < data.layers; ++i) {
245 for (
size_t j = 0; j < data.levels; ++j) {
247 glTexSubImage3D(target,
static_cast<GLint
>(j),
248 0, 0,
static_cast<GLint
>(layer_offset+i), ext.width, ext.height, 1,
249 pixelFormat, pixelType, data.getData(i, 0, j));
253 case GL_TEXTURE_2D_MULTISAMPLE:
256 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
260 for (
size_t j = 0; j < data.levels; ++j) {
262 glTexSubImage3D(target,
static_cast<GLint
>(j),
263 0, 0, 0, ext.width, ext.height, ext.depth,
264 pixelFormat, pixelType, data.getData(0, 0, j));
267 case GL_TEXTURE_CUBE_MAP:
268 for (
size_t j = 0; j < data.levels; ++j) {
269 for (GLint c = 0; c < 6; ++c) {
271 glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + c, (GLint)j,
272 0, 0, ext.width, ext.height,
273 pixelFormat, pixelType, data.getData(0, c, j));
277 case GL_TEXTURE_CUBE_MAP_ARRAY:
278 for (
size_t i = 0; i < data.layers; ++i) {
279 for (
size_t j = 0; j < data.levels; ++j) {
280 for (GLint c = 0; c < 6; ++c) {
282 glTexSubImage3D(target, (GLint)j,
283 0, 0, (GLint)(layer_offset+i)*6 + c, ext.width, ext.height, 1,
284 pixelFormat, pixelType, data.getData(i, c, j));
289 case GL_INVALID_ENUM:
296 glGenerateMipmap(target);
301 uint32_t layer_offset,
302 uint32_t face_offset,
303 uint32_t level_offset)
305 TextureGL20 & texture = this->textures[textureHandle];
306 const GLenum target = texture.type;
307 glBindTexture(target, texture.textureId);
308 uploadTextureData(texture, data, layer_offset, face_offset, level_offset);
309 glBindTexture(target, 0);
315 glGenSamplers(1, &sampler);
317 glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, OpenGL20::AddressModes[state.
addressModeS]);
318 glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, OpenGL20::AddressModes[state.
addressModeT]);
319 glSamplerParameteri(sampler, GL_TEXTURE_WRAP_R, OpenGL20::AddressModes[state.
addressModeW]);
321 glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, OpenGL20::MipMinFilterModes[state.
filter]);
322 glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, OpenGL20::MagFilterModes[state.
filter]);
324 glSamplerParameterfv(sampler, GL_TEXTURE_BORDER_COLOR, state.
borderColor);
327 glSamplerParameteri(sampler, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
329 glSamplerParameteri(sampler, GL_TEXTURE_COMPARE_MODE, GL_NONE);
332 glSamplerParameteri(sampler, GL_TEXTURE_COMPARE_FUNC, OpenGL20::ComparisonFunctions[state.
comparisonFunction]);
335 glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT,
static_cast<float>(state.
maxAnisotropy));
336 }
else if (useAnisotropic) {
337 glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
345 const GLuint sampler =
static_cast<GLuint
>(handle.
handle);
346 glDeleteSamplers(1, &sampler);
351 TextureGL20 & texture = this->textures[desc.texture];
353 textureView.arraySize = desc.numLayers;
354 if(desc.numLevels <= 1) textureView.hasMipmaps =
false;
355 textureView.textureView =
true;
357 if(desc.numLayers == 1){
358 if(textureView.type == GL_TEXTURE_1D_ARRAY)
359 textureView.type = GL_TEXTURE_1D;
360 if(textureView.type == GL_TEXTURE_2D_ARRAY)
361 textureView.type = GL_TEXTURE_2D;
362 if(textureView.type == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
363 textureView.type = GL_TEXTURE_2D_MULTISAMPLE;
364 if(textureView.type == GL_TEXTURE_CUBE_MAP_ARRAY)
365 textureView.type = GL_TEXTURE_CUBE_MAP;
368 glGenTextures(1, &textureView.textureId);
372 const GLenum textureFormat = OpenGL20::TextureFormats[(int)texture.format];
373 glTextureView(textureView.textureId,
388 GLenum target = textureView.type;
389 glBindTexture(target, textureView.textureId);
391 glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
392 if (!texture.hasMipmaps) {
395 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
398 glBindTexture(target, 0);
400 return TextureViewHandle(this->textures.addResource(std::move(textureView)).handle);
406 glDeleteTextures(1, &textureView.textureId);
412 TextureGL20 & texture = this->textures[texureHandle];
413 GLenum target = texture.type;
414 glBindTexture(target, texture.textureId);
415 glGenerateMipmap(target);
416 texture.hasMipmaps =
true;
417 glBindTexture(target, 0);
422 std::vector<TextureHandle> handles;
424 handles.push_back(textures.getHandle(texture));
427 releaseTexture(handle);
435 glObjectLabel(GL_TEXTURE, texture.textureId,
static_cast<GLsizei
>(name.
size()), name.
data());
Log implementation class.
Provides a weakly referenced view over the contents of a string.
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
constexpr size_t size() const noexcept
Get the size of the string.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
handle_type handle
Internal resource handle.
static const Handle_t InvalidHandle
Represents an invalid handle.
Encapsulates state for texture sampling in a state object.
ComparisonFunction comparisonFunction
Specifies the comparison function to use when applying a comparison sampler.
unsigned int maxAnisotropy
Specifies the maximum number of anisotropic samples to use when sampling a texture.
AddressMode addressModeW
Specifies the addressing mode along the W axis in texture coordinate space.
AddressMode addressModeS
Specifies the addressing mode along the S axis in texture coordinate space.
@ ComparisonMinMagMipPoint
Comparison filter for depth sample comparisons using point sampling.
@ ComparisonMinMagMipLinear
Comparison filter for depth sample comparisons using linear interpolation sampling.
FilterMode filter
Specifies the filter to use for texture sampling.
AddressMode addressModeT
Specifies the addressing mode along the T axis in texture coordinate space.
@ GenerateMipMaps
The texture supports automatic mipmap generation performed by the graphics device.
Describes how to fetch data from a texture in shaders.
void releaseSamplerState(SamplerStateHandle handle) override
Release the sampler state with the given handle.
SamplerStateHandle loadSamplerState(const SamplerState &state) override
Load a sampler state object.
void generateMipmaps(TextureHandle texureHandle) override
Use the graphics device to generate mipmaps for the texture with the given texture handle.
TextureViewHandle createTextureView(TextureViewDescription &viewDescription) override
Create a texture view used to bind a limited view of the texture data to the rendering pipeline.
void releaseTextureView(const TextureViewHandle &handle) override
Release the given texture view.
void annotate(TextureHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
void releaseResources() override
Release all allocated texture resources.
TextureHandle loadTexture(const TextureDescription &desc, const TextureData *data) override
Load a texture from the given description.
void releaseTexture(TextureHandle textureHandle) override
Release the texture with the given textureHandle.