2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "gles-graphics-texture.h"
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/gl-abstraction.h>
24 #include <dali/integration-api/gl-defines.h>
28 #include "egl-graphics-controller.h"
29 #include "gles-graphics-sampler.h"
30 #include "gles-graphics-types.h"
34 // These match the GL specification
35 //const int32_t GL_MINIFY_DEFAULT = GL_NEAREST_MIPMAP_LINEAR;
36 //const int32_t GL_MAGNIFY_DEFAULT = GL_LINEAR;
37 const int32_t GL_WRAP_DEFAULT = GL_CLAMP_TO_EDGE;
39 // These are the Dali defaults
40 const int32_t DALI_MINIFY_DEFAULT = GL_LINEAR;
41 const int32_t DALI_MAGNIFY_DEFAULT = GL_LINEAR;
44 namespace Dali::Graphics::GLES
46 struct ColorConversion
50 std::vector<uint8_t> (*pConversionFunc)(const void*, uint32_t, uint32_t, uint32_t, uint32_t);
51 void (*pConversionWriteFunc)(const void*, uint32_t, uint32_t, uint32_t, uint32_t, void*);
54 inline void WriteRGB32ToRGBA32(const void* pData, uint32_t sizeInBytes, uint32_t width, uint32_t height, uint32_t rowStride, void* pOutput)
56 auto inData = reinterpret_cast<const uint8_t*>(pData);
57 auto outData = reinterpret_cast<uint8_t*>(pOutput);
59 for(auto i = 0u; i < sizeInBytes; i += 3)
61 outData[outIdx] = inData[i];
62 outData[outIdx + 1] = inData[i + 1];
63 outData[outIdx + 2] = inData[i + 2];
64 outData[outIdx + 3] = 0xff;
70 * Converts RGB to RGBA
72 inline std::vector<uint8_t> ConvertRGB32ToRGBA32(const void* pData, uint32_t sizeInBytes, uint32_t width, uint32_t height, uint32_t rowStride)
74 std::vector<uint8_t> rgbaBuffer{};
75 rgbaBuffer.resize(width * height * 4);
76 WriteRGB32ToRGBA32(pData, sizeInBytes, width, height, rowStride, &rgbaBuffer[0]);
81 * Format conversion table
83 static const std::vector<ColorConversion> COLOR_CONVERSION_TABLE = {
84 {Format::R8G8B8_UNORM, Format::R8G8B8A8_UNORM, ConvertRGB32ToRGBA32, WriteRGB32ToRGBA32}};
89 Texture::Texture(const Graphics::TextureCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
90 : TextureResource(createInfo, controller)
92 // If there is any data, move it into staging buffer
93 if(mCreateInfo.data && mCreateInfo.dataSize)
95 mStagingBuffer.resize(size_t(mCreateInfo.dataSize));
96 std::copy(reinterpret_cast<char*>(mCreateInfo.data),
97 reinterpret_cast<char*>(mCreateInfo.data) + mCreateInfo.dataSize,
98 mStagingBuffer.begin());
101 // Add texture to the Resource queue
102 mController.AddTexture(*this);
105 bool Texture::InitializeResource()
107 if(mCreateInfo.nativeImagePtr)
109 return InitializeNativeImage();
111 return InitializeTexture();
114 bool Texture::InitializeNativeImage()
116 auto gl = mController.GetGL();
121 // Do nothing during shutdown
125 NativeImageInterfacePtr nativeImage = mCreateInfo.nativeImagePtr;
126 bool created = nativeImage->CreateResource();
127 mGlTarget = nativeImage->GetTextureTarget();
130 gl->GenTextures(1, &texture);
131 gl->BindTexture(mGlTarget, texture);
133 gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1); // We always use tightly packed data
135 // Apply default sampling parameters
136 gl->TexParameteri(mGlTarget, GL_TEXTURE_MIN_FILTER, DALI_MINIFY_DEFAULT);
137 gl->TexParameteri(mGlTarget, GL_TEXTURE_MAG_FILTER, DALI_MAGNIFY_DEFAULT);
138 gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT);
139 gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT);
141 // platform specific implementation decides on what GL extension to use
142 if(nativeImage->TargetTexture() != 0u)
144 gl->DeleteTextures(1, &texture);
145 nativeImage->DestroyResource();
151 mTextureId = texture;
156 DALI_LOG_ERROR("Native Image: InitializeNativeImage, CreateResource() failed\n");
159 return created; // WARNING! May be false! Needs handling! (Well, initialized on bind)
162 bool Texture::InitializeTexture()
164 auto gl = mController.GetGL();
167 // Do nothing during shutdown
173 mGlTarget = GLTextureTarget(mCreateInfo.textureType).target;
174 mIsCompressed = Graphics::GLES::FormatCompression(mCreateInfo.format).compressed;
176 switch(mCreateInfo.textureType)
179 case Graphics::TextureType::TEXTURE_2D:
181 Graphics::GLES::GLTextureFormatType format(mCreateInfo.format);
183 // TODO: find better condition, with this test the L8 doesn't work
184 if(1) //format.format && format.type)
187 gl->GenTextures(1, &texture);
188 gl->BindTexture(GL_TEXTURE_2D, texture);
190 // Allocate memory for the texture
193 gl->TexImage2D(GL_TEXTURE_2D,
195 format.internalFormat,
196 mCreateInfo.size.width,
197 mCreateInfo.size.height,
201 (mCreateInfo.data ? mStagingBuffer.data() : nullptr));
205 gl->CompressedTexImage2D(GL_TEXTURE_2D,
207 format.internalFormat,
208 mCreateInfo.size.width,
209 mCreateInfo.size.height,
211 mCreateInfo.dataSize,
212 (mCreateInfo.data ? mStagingBuffer.data() : nullptr));
215 // Clear staging buffer if there was any
216 mStagingBuffer.clear();
217 mTextureId = texture;
219 // Default texture filtering (to be set later via command buffer binding)
220 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
221 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
222 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT);
223 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT);
228 case Graphics::TextureType::TEXTURE_CUBEMAP:
230 Graphics::GLES::GLTextureFormatType format(mCreateInfo.format);
232 if(format.format && format.type)
235 gl->GenTextures(1, &texture);
236 gl->BindTexture(GL_TEXTURE_CUBE_MAP, texture);
237 gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1); // We always use tightly packed data
239 gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
240 gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
241 gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT);
242 gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT);
244 // Allocate memory for the texture
245 for(uint32_t i = 0; i < 6; ++i)
249 gl->TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
251 format.internalFormat,
252 mCreateInfo.size.width,
253 mCreateInfo.size.height,
257 (mCreateInfo.data ? mStagingBuffer.data() : nullptr));
261 gl->CompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
263 format.internalFormat,
264 mCreateInfo.size.width,
265 mCreateInfo.size.height,
267 mCreateInfo.dataSize,
268 (mCreateInfo.data ? mStagingBuffer.data() : nullptr));
272 // Clear staging buffer if there was any
273 mStagingBuffer.clear();
275 mTextureId = texture;
277 gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_WRAP_DEFAULT);
289 void Texture::DestroyResource()
291 auto gl = mController.GetGL();
297 // This is a proper destructor
300 gl->DeleteTextures(1, &mTextureId);
302 if(mCreateInfo.nativeImagePtr)
304 mCreateInfo.nativeImagePtr->DestroyResource();
308 void Texture::DiscardResource()
310 mController.DiscardResource(this);
313 void Texture::Bind(const TextureBinding& binding) const
315 auto gl = mController.GetGL();
318 // Do nothing during shutdown
322 gl->ActiveTexture(GL_TEXTURE0 + binding.binding);
323 gl->BindTexture(mGlTarget, mTextureId);
325 // For GLES2 if there is a sampler set in the binding
329 auto* sampler = static_cast<const GLES::Sampler*>(binding.sampler);
330 const auto& samplerCreateInfo = sampler->GetCreateInfo();
332 auto mipMapMode = samplerCreateInfo.mipMapMode;
334 gl->TexParameteri(mGlTarget, GL_TEXTURE_MIN_FILTER, GLSamplerFilterAndMipMapMode(samplerCreateInfo.minFilter, mipMapMode).glFilter);
335 gl->TexParameteri(mGlTarget, GL_TEXTURE_MAG_FILTER, GLSamplerFilter(samplerCreateInfo.magFilter).glFilter);
336 gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_S, GLAddressMode(samplerCreateInfo.addressModeU).texParameter);
337 gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_T, GLAddressMode(samplerCreateInfo.addressModeV).texParameter);
338 if(mGlTarget == GL_TEXTURE_CUBE_MAP)
340 gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_R, GLAddressMode(samplerCreateInfo.addressModeW).texParameter);
345 gl->TexParameteri(mGlTarget, GL_TEXTURE_MIN_FILTER, DALI_MINIFY_DEFAULT);
346 gl->TexParameteri(mGlTarget, GL_TEXTURE_MAG_FILTER, DALI_MAGNIFY_DEFAULT);
347 gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT);
348 gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT);
349 if(mGlTarget == GL_TEXTURE_CUBE_MAP)
351 gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_R, GL_WRAP_DEFAULT);
357 gl->TexParameteri(mGlTarget, GL_TEXTURE_MAX_LEVEL, mMaxMipMapLevel);
361 void Texture::Prepare()
363 NativeImageInterfacePtr nativeImage = mCreateInfo.nativeImagePtr;
366 if(nativeImage->SourceChanged())
369 uint32_t width = mCreateInfo.nativeImagePtr->GetWidth();
370 uint32_t height = mCreateInfo.nativeImagePtr->GetHeight();
371 mCreateInfo.SetSize({width, height}); // Size may change
374 nativeImage->PrepareTexture();
379 * This function tests whether format is supported by the driver. If possible it applies
380 * format conversion to suitable supported pixel format.
382 bool Texture::TryConvertPixelData(const void* pData, Graphics::Format srcFormat, Graphics::Format destFormat, uint32_t sizeInBytes, uint32_t width, uint32_t height, std::vector<uint8_t>& outputBuffer)
384 // No need to convert
385 if(srcFormat == destFormat)
390 auto it = std::find_if(COLOR_CONVERSION_TABLE.begin(), COLOR_CONVERSION_TABLE.end(), [&](auto& item) {
391 return item.srcFormat == srcFormat && item.destFormat == destFormat;
394 // No suitable format, return empty array
395 if(it == COLOR_CONVERSION_TABLE.end())
399 auto begin = reinterpret_cast<const uint8_t*>(pData);
401 outputBuffer = std::move(it->pConversionFunc(begin, sizeInBytes, width, height, 0u));
402 return !outputBuffer.empty();
405 } // namespace Dali::Graphics::GLES