Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
glTexture.cpp
Go to the documentation of this file.
1
2
3#include "config.h"
4
5#include "Headers/glTexture.h"
10
11namespace Divide {
12
14
15 : Texture(context, descriptor)
16 , _type( gl46core::GL_NONE )
17{
18}
19
21{
22 unload();
23}
24
26{
27 if (_textureHandle > 0u)
28 {
29 if (GL_API::GetStateTracker().unbindTexture(_descriptor._texType, _textureHandle))
30 {
31 NOP();
32 }
33
34 gl46core::glDeleteTextures(1, &_textureHandle);
35 _textureHandle = GL_NULL_HANDLE;
36 }
37
38 return Texture::unload();
39}
40
42{
44
45 if (_loadSync != nullptr)
46 {
47 gl46core::glWaitSync(_loadSync, gl46core::UnusedMask::GL_UNUSED_BIT, gl46core::GL_TIMEOUT_IGNORED);
49 }
50
51 return Texture::postLoad();
52}
53
55{
56 DIVIDE_ASSERT(!_hasStorage && "glTexture::reserveStorage error: double call detected!");
57
58 const GLUtil::FormatAndDataType glInternalFormat = GLUtil::InternalFormatAndDataType( _descriptor._baseFormat, _descriptor._dataType, _descriptor._packing );
59 const gl46core::GLuint msaaSamples = static_cast<gl46core::GLuint>(_descriptor._msaaSamples);
60 const bool isCubeMap = IsCubeTexture( _descriptor._texType );
61 DIVIDE_ASSERT(!(isCubeMap && _width != _height) && "glTexture::reserverStorage error: width and height for cube map texture do not match!");
62
63 switch (_descriptor._texType )
64 {
66 {
67 assert(_depth == 1u);
68 gl46core::glTextureStorage1D( _loadingHandle,
69 mipCount(),
70 glInternalFormat._format,
71 _width );
72
73 } break;
77 {
78 DIVIDE_ASSERT(_descriptor._texType == TextureType::TEXTURE_1D_ARRAY || _depth == 1u);
79 if (msaaSamples == 0u) {
80 gl46core::glTextureStorage2D( _loadingHandle,
81 mipCount(),
82 glInternalFormat._format,
83 _width,
84 _descriptor._texType == TextureType::TEXTURE_1D_ARRAY ? _depth : _height );
85 } else {
86 gl46core::glTextureStorage2DMultisample( _loadingHandle,
87 msaaSamples,
88 glInternalFormat._format,
89 _width,
90 _descriptor._texType == TextureType::TEXTURE_1D_ARRAY ? _depth : _height,
91 gl46core::GL_TRUE );
92 }
93 } break;
95 {
96 if (msaaSamples == 0u)
97 {
98 gl46core::glTextureStorage3D( _loadingHandle,
99 mipCount(),
100 glInternalFormat._format,
101 _width,
102 _height,
103 _depth );
104 }
105 else
106 {
107 gl46core::glTextureStorage3DMultisample( _loadingHandle,
108 msaaSamples,
109 glInternalFormat._format,
110 _width,
111 _height,
112 _depth,
113 gl46core::GL_TRUE );
114 }
115 } break;
118 {
119 const U32 layerCount = isCubeMap ? _depth * 6 : _depth;
120
121 if (msaaSamples == 0u)
122 {
123 gl46core::glTextureStorage3D( _loadingHandle,
124 mipCount(),
125 glInternalFormat._format,
126 _width,
127 _height,
128 layerCount );
129 }
130 else
131 {
132 gl46core::glTextureStorage3DMultisample( _loadingHandle,
133 msaaSamples,
134 glInternalFormat._format,
135 _width,
136 _height,
137 layerCount,
138 gl46core::GL_TRUE );
139 }
140 } break;
141 default: DIVIDE_UNEXPECTED_CALL(); break;
142 }
143
144 _hasStorage = true;
145}
146
147void glTexture::prepareTextureData(const U16 width, const U16 height, const U16 depth, [[maybe_unused]] const bool emptyAllocation)
148{
149 Texture::prepareTextureData(width, height, depth, emptyAllocation);
150
151 _type = GLUtil::internalTextureType( _descriptor._texType, _descriptor._msaaSamples );
152
153 gl46core::glCreateTextures(_type, 1, &_loadingHandle);
154 _hasStorage = false;
155
156 assert(_loadingHandle != 0 && "glTexture error: failed to generate new texture handle!");
158 {
159 gl46core::glObjectLabel( gl46core::GL_TEXTURE, _loadingHandle, -1, resourceName().c_str());
160 }
161
163}
164
166{
167 gl46core::glTextureParameteri(_loadingHandle, gl46core::GL_TEXTURE_BASE_LEVEL, _descriptor._mipBaseLevel );
168 gl46core::glTextureParameteri( _loadingHandle, gl46core::GL_TEXTURE_MAX_LEVEL, mipCount());
169
170 if ( _descriptor._mipMappingState == MipMappingState::AUTO)
171 {
172 gl46core::glGenerateTextureMipmap(_loadingHandle);
173 }
174
175 if (_textureHandle > 0u)
176 {
177 // Immutable storage requires us to create a new texture object
178 gl46core::glDeleteTextures(1, &_textureHandle);
179 }
180
181 _textureHandle = _loadingHandle;
183 {
184 if (_loadSync != nullptr)
185 {
187 }
189 gl46core::glFlush();
190 }
191
193}
194
195void glTexture::loadDataInternal(const ImageTools::ImageData& imageData, const vec3<U16>& offset, const PixelAlignment& pixelUnpackAlignment )
196{
197 const U32 numLayers = imageData.layerCount();
198 const U8 numMips = imageData.mipCount();
199
200 for ( U32 l = 0u; l < numLayers; ++l )
201 {
202 const ImageTools::ImageLayer& layer = imageData.imageLayers()[l];
203 for ( U8 m = 0u; m < numMips; ++m )
204 {
205 const ImageTools::LayerData* mip = layer.getMip( m );
206 assert( mip->_size > 0u );
207
208 loadDataInternal((Byte*)mip->data(), mip->_size, m, vec3<U16>{offset.x, offset.y, offset.z + l}, mip->_dimensions, pixelUnpackAlignment);
209 }
210 }
211}
212
213void glTexture::loadDataInternal( const Byte* data, const size_t size, const U8 targetMip, const vec3<U16>& offset, const vec3<U16>& dimensions, const PixelAlignment& pixelUnpackAlignment )
214{
215 const bool isCompressed = IsCompressed( _descriptor._baseFormat );
216
217 const GLUtil::FormatAndDataType formatAndType = GLUtil::InternalFormatAndDataType( _descriptor._baseFormat, _descriptor._dataType, _descriptor._packing );
218
219 DIVIDE_ASSERT( _descriptor._msaaSamples == 0u || data == nullptr);
220
221 if ( _descriptor._packing == GFXImagePacking::RGBA_4444 )
222 {
223 constexpr PixelAlignment customAlignment{ ._alignment = 2u };
225 }
226 else
227 {
228 GL_API::GetStateTracker().setPixelUnpackAlignment( pixelUnpackAlignment );
229 }
230
231 switch ( _descriptor._texType )
232 {
234 {
235 assert(offset.z == 0u);
236
237 if (isCompressed)
238 {
239 gl46core::glCompressedTextureSubImage1D(_loadingHandle, targetMip, offset.x, dimensions.width, formatAndType._internalFormat, static_cast<gl46core::GLsizei>(size), data);
240 }
241 else
242 {
243 gl46core::glTextureSubImage1D(_loadingHandle, targetMip, offset.x, dimensions.width, formatAndType._internalFormat, formatAndType._dataType, data);
244 }
245 } break;
248 {
249 assert( offset.z == 0u );
250
251 if (isCompressed)
252 {
253 gl46core::glCompressedTextureSubImage2D(_loadingHandle, targetMip, offset.x, offset.y, dimensions.width, dimensions.height, formatAndType._internalFormat, static_cast<gl46core::GLsizei>(size), data);
254 }
255 else
256 {
257 gl46core::glTextureSubImage2D(_loadingHandle, targetMip, offset.x, _descriptor._texType == TextureType::TEXTURE_1D_ARRAY ? offset.z : offset.y, dimensions.width, dimensions.height, formatAndType._internalFormat, formatAndType._dataType, data);
258 }
259 } break;
264 {
265 if (isCompressed)
266 {
267 gl46core::glCompressedTextureSubImage3D(_loadingHandle, targetMip, offset.x, offset.y, offset.z, dimensions.width, dimensions.height, dimensions.depth, formatAndType._internalFormat, static_cast<gl46core::GLsizei>(size), data);
268 }
269 else
270 {
271 gl46core::glTextureSubImage3D(_loadingHandle, targetMip, offset.x, offset.y, offset.z, dimensions.width, dimensions.height, dimensions.depth, formatAndType._internalFormat, formatAndType._dataType, data);
272 }
273 } break;
274 default: break;
275 }
276
278}
279
280void glTexture::clearData( const UColour4& clearColour, SubRange layerRange, U8 mipLevel ) const
281{
282 FColour4 floatData;
283 vec4<U16> shortData;
284 vec4<U32> intData;
285
286 const auto GetClearData = [clearColour, &floatData, &shortData, &intData](const GFXDataFormat format)
287 {
288 switch (format)
289 {
292 {
293 return (bufferPtr)clearColour._v;
294 }
297 {
298 shortData = { clearColour.r, clearColour.g, clearColour.b, clearColour.a };
299 return (bufferPtr)shortData._v;
300 }
301
304 {
305 intData = { clearColour.r, clearColour.g, clearColour.b, clearColour.a };
306 return (bufferPtr)intData._v;
307 }
308
311 {
312 floatData = Util::ToFloatColour(clearColour);
313 return (bufferPtr)floatData._v;
314 }
316 {
318 } break;
319 }
320
321 return (bufferPtr)nullptr;
322 };
323
324 if ( mipLevel== U8_MAX )
325 {
326 assert(mipCount() > 0u);
327 mipLevel = to_U8(mipCount() - 1u);
328 }
329
330 DIVIDE_ASSERT(!IsCompressed( _descriptor._baseFormat ), "glTexture::clearData: compressed textures are not supported!");
331
332 const GLUtil::FormatAndDataType formatAndType = GLUtil::InternalFormatAndDataType( _descriptor._baseFormat, _descriptor._dataType, _descriptor._packing );
333
334 if ( layerRange._offset == 0u && (layerRange._count == U16_MAX || layerRange._count == _depth))
335 {
336 gl46core::glClearTexImage( _textureHandle, mipLevel, formatAndType._internalFormat, formatAndType._dataType, GetClearData( _descriptor._dataType ) );
337 }
338 else
339 {
340 if ( layerRange._count >= _depth )
341 {
342 layerRange._count = _depth;
343 }
344
345 const bool isCubeMap = IsCubeTexture( _descriptor._texType );
346 const U32 layerOffset = isCubeMap ? layerRange._offset * 6 : layerRange._offset;
347 const U32 depth = isCubeMap ? layerRange._count * 6 : layerRange._count;
348 const U16 mipWidth = _width >> mipLevel;
349 const U16 mipHeight = _height >> mipLevel;
350
351 gl46core::glClearTexSubImage( _textureHandle,
352 mipLevel,
353 0,
354 _descriptor._texType == TextureType::TEXTURE_1D_ARRAY ? layerRange._offset : 0,
355 layerOffset,
356 mipWidth,
357 _descriptor._texType == TextureType::TEXTURE_1D_ARRAY ? layerRange._count : mipHeight,
358 depth,
359 formatAndType._internalFormat,
360 formatAndType._dataType,
361 GetClearData( _descriptor._dataType) );
362
363 }
364}
365
366/*static*/ void glTexture::Copy(const glTexture* source, const U8 sourceSamples, const glTexture* destination, const U8 destinationSamples, const CopyTexParams& params)
367{
369
370 // We could handle this with a custom shader pass and temp render targets, so leaving the option i
371 DIVIDE_ASSERT(sourceSamples == destinationSamples == 0u, "glTexture::copy Multisampled textures is not supported yet!");
372 DIVIDE_ASSERT(source != nullptr && destination != nullptr, "glTexture::copy Invalid source and/or destination textures specified!");
373
374 const TextureType srcType = source->_descriptor._texType;
375 const TextureType dstType = destination->_descriptor._texType;
376 assert(srcType != TextureType::COUNT && dstType != TextureType::COUNT);
377
378 if (srcType != TextureType::COUNT && dstType != TextureType::COUNT)
379 {
380 U32 layerOffset = params._layerRange.offset;
381 U32 layerCount = params._layerRange.count == U16_MAX ? source->_depth : params._layerRange.count;
382 if (IsCubeTexture(srcType))
383 {
384 layerOffset *= 6;
385 layerCount *= 6;
386 }
387
388 gl46core::glCopyImageSubData(
389 //Source
390 source->textureHandle(),
391 GLUtil::internalTextureType(srcType, sourceSamples),
392 params._sourceMipLevel,
393 params._sourceCoords.x,
394 params._sourceCoords.y,
395 layerOffset,
396 //Destination
397 destination->textureHandle(),
398 GLUtil::internalTextureType(dstType, destinationSamples),
399 params._targetMipLevel,
400 params._targetCoords.x,
401 params._targetCoords.y,
402 layerOffset,
403 //Source Dim
404 params._dimensions.x,
405 params._dimensions.y,
406 layerCount);
407 }
408}
409
410ImageReadbackData glTexture::readData(U8 mipLevel, const PixelAlignment& pixelPackAlignment) const
411{
412 ImageReadbackData grabData{};
413
414 grabData._bpp = Texture::GetBytesPerPixel( _descriptor._dataType, _descriptor._baseFormat, _descriptor._packing );
415 grabData._numComponents = numChannels();
416 grabData._sourceIsBGR = IsBGRTexture( _descriptor._baseFormat );
417
418 DIVIDE_ASSERT(_depth == 1u && !IsCubeTexture( _descriptor._texType ), "glTexture:readData: unsupported image for readback. Support is very limited!");
419
420 mipLevel = std::min(mipLevel, to_U8(mipCount() - 1u));
421 if ( IsCompressed( _descriptor._baseFormat ) )
422 {
423 gl46core::GLint compressedSize = 0;
424 gl46core::glGetTextureLevelParameteriv(_textureHandle, static_cast<gl46core::GLint>(mipLevel) , gl46core::GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compressedSize);
425 if ( compressedSize > 0 )
426 {
427 grabData._data.resize(compressedSize);
428 gl46core::glGetCompressedTextureImage( _textureHandle, mipLevel, compressedSize, (bufferPtr)grabData._data.data() );
429 }
430 }
431 else
432 {
433 grabData._numComponents = 4; //glGetTextureImage pads the data to RGBA
434 {
435 gl46core::GLint width = _width, height = _height;
436 gl46core::glGetTextureLevelParameteriv(_textureHandle, static_cast<gl46core::GLint>(mipLevel), gl46core::GL_TEXTURE_WIDTH, &width );
437 gl46core::glGetTextureLevelParameteriv(_textureHandle, static_cast<gl46core::GLint>(mipLevel), gl46core::GL_TEXTURE_HEIGHT, &height );
438 grabData._width = to_U16(width);
439 grabData._height = to_U16(height);
440 }
441
442 const U8 storagePerComponent = grabData._bpp / numChannels();
443 grabData._data.resize( to_size( grabData._width ) * grabData._height * _depth * storagePerComponent * 4 );
444
446
447 const GLUtil::FormatAndDataType formatAndType = GLUtil::InternalFormatAndDataType( _descriptor._baseFormat, _descriptor._dataType, _descriptor._packing );
448
449 gl46core::glGetTextureImage( _textureHandle,
450 mipLevel,
451 formatAndType._internalFormat,
452 formatAndType._dataType,
453 (gl46core::GLsizei)grabData._data.size(),
454 grabData._data.data() );
455
457 }
458
459 return grabData;
460}
461
462};
#define DIVIDE_ASSERT(...)
#define DIVIDE_UNEXPECTED_CALL()
#define NOP()
#define PROFILE_SCOPE_AUTO(CATEGORY)
Definition: Profiler.h:87
virtual bool unload()
Definition: Resource.cpp:65
static void DestroyFenceSync(gl46core::GLsync &sync)
Definition: GLWrapper.cpp:1998
static gl46core::GLsync CreateFenceSync()
Definition: GLWrapper.cpp:1988
static GLStateTracker & GetStateTracker() noexcept
Definition: GLWrapper.cpp:1749
An API-independent representation of a texture.
Definition: Texture.h:83
virtual void submitTextureData()
Definition: Texture.cpp:339
virtual void prepareTextureData(U16 width, U16 height, U16 depth, bool emptyAllocation)
Definition: Texture.cpp:324
U8 numChannels() const noexcept
Definition: Texture.cpp:282
static U8 GetBytesPerPixel(GFXDataFormat format, GFXImageFormat baseFormat, GFXImagePacking packing) noexcept
Definition: Texture.cpp:105
bool postLoad() override
Definition: Texture.cpp:212
void loadDataInternal(const ImageTools::ImageData &imageData, const vec3< U16 > &offset, const PixelAlignment &pixelUnpackAlignment) override
Definition: glTexture.cpp:195
~glTexture() override
Definition: glTexture.cpp:20
bool unload() override
Definition: glTexture.cpp:25
gl46core::GLsync _loadSync
Definition: glTexture.h:70
ImageReadbackData readData(U8 mipLevel, const PixelAlignment &pixelPackAlignment) const override
Definition: glTexture.cpp:410
gl46core::GLenum _type
Definition: glTexture.h:68
void submitTextureData() override
Definition: glTexture.cpp:165
gl46core::GLuint _loadingHandle
Definition: glTexture.h:69
static void Copy(const glTexture *source, U8 sourceSamples, const glTexture *destination, U8 destinationSamples, const CopyTexParams &params)
Definition: glTexture.cpp:366
void reserveStorage()
Definition: glTexture.cpp:54
void clearData(const UColour4 &clearColour, SubRange layerRange, U8 mipLevel) const
Definition: glTexture.cpp:280
void prepareTextureData(U16 width, U16 height, U16 depth, bool emptyAllocation) override
Definition: glTexture.cpp:147
glTexture(PlatformContext &context, const ResourceDescriptor< Texture > &descriptor)
Definition: glTexture.cpp:13
bool postLoad() override
Definition: glTexture.cpp:41
constexpr bool ENABLE_GPU_VALIDATION
Error callbacks, validations, buffer checks, etc. are controlled by this flag. Heavy performance impa...
Definition: config.h:192
gl46core::GLenum internalTextureType(const TextureType type, const U8 msaaSamples)
FormatAndDataType InternalFormatAndDataType(const GFXImageFormat baseFormat, const GFXDataFormat dataType, const GFXImagePacking packing) noexcept
constexpr Optick::Category::Type Graphics
Definition: Profiler.h:60
bool isMainThread() noexcept
FColour4 ToFloatColour(const UColour4 &byteColour) noexcept
Definition: MathHelper.cpp:268
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
std::byte Byte
constexpr U16 to_U16(const T value)
uint8_t U8
bool IsCubeTexture(TextureType texType) noexcept
constexpr gl46core::GLuint GL_NULL_HANDLE
Invalid object value. Used to compare handles and determine if they were properly created.
Definition: glResources.h:105
constexpr U16 U16_MAX
uint16_t U16
constexpr U8 U8_MAX
constexpr U8 to_U8(const T value)
constexpr size_t to_size(const T value)
bool IsCompressed(GFXImageFormat format) noexcept
uint32_t U32
void * bufferPtr
bool IsBGRTexture(GFXImageFormat format) noexcept
vec2< U16 > _layerRange
Definition: TextureData.h:40
vec2< U32 > _sourceCoords
Definition: TextureData.h:41
vec2< U32 > _targetCoords
Definition: TextureData.h:42
vec2< U16 > _dimensions
Definition: TextureData.h:43
bool setPixelPackAlignment(const PixelAlignment &pixelPackAlignment)
Pixel pack alignment is usually changed by textures, PBOs, etc.
bool setPixelUnpackAlignment(const PixelAlignment &pixelUnpackAlignment)
Pixel unpack alignment is usually changed by textures, PBOs, etc.
U8 mipCount() const
get the number of pre-loaded mip maps (same number for each layer)
Definition: ImageTools.h:149
U16 layerCount() const noexcept
get the total number of image layers
Definition: ImageTools.h:151
const vector< ImageLayer > & imageLayers() const noexcept
Definition: ImageTools.h:136
LayerData * getMip(const U8 mip) const
Definition: ImageTools.h:105
virtual bufferPtr data() const =0
size_t _size
the image data as it was read from the file / memory.
Definition: ImageTools.h:46
vec3< U16 > _dimensions
with and height
Definition: ImageTools.h:48