Chromium Code Reviews| Index: src/gpu/gl/GrGLGpu.cpp |
| diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp |
| index 071b11383d1691cf134207da8efeaaaefec8fb41..13153bc719be72188a445e2a77352326ab652b8b 100644 |
| --- a/src/gpu/gl/GrGLGpu.cpp |
| +++ b/src/gpu/gl/GrGLGpu.cpp |
| @@ -912,11 +912,32 @@ static inline GrGLenum check_alloc_error(const GrSurfaceDesc& desc, |
| } |
| /** |
| + * Determines if TexStorage can be used when creating a texture. |
| + * |
| + * @param caps The capabilities of the GL device. |
| + * @param standard The GL standard in use. |
| + * @param desc The surface descriptor for the texture being created. |
| + */ |
| +static bool can_use_tex_storage(const GrGLCaps& caps, const GrGLStandard& standard, |
| + const GrSurfaceDesc& desc) { |
| + bool canUseTexStorage = caps.texStorageSupport(); |
| + if (canUseTexStorage && kGL_GrGLStandard == standard) { |
| + // 565 is not a sized internal format on desktop GL. So on desktop with |
|
bsalomon
2016/02/26 22:09:54
We now are making most decisions about configs in
cblume
2016/02/27 00:49:54
Done.
|
| + // 565 we always use an unsized internal format to let the system pick |
| + // the best sized format to convert the 565 data to. Since TexStorage |
| + // only allows sized internal formats we will instead use TexImage2D. |
| + canUseTexStorage = desc.fConfig != kRGB_565_GrPixelConfig; |
| + } |
| + |
| + return canUseTexStorage; |
| +} |
| + |
| +/** |
| * Creates storage space for the texture and fills it with texels. |
| * |
| * @param desc The surface descriptor for the texture being created. |
| * @param interface The GL interface in use. |
| - * @param target The GL target to which the texture is bound |
| + * @param useTexStorage The result of a call to can_use_tex_storage(). |
| * @param internalFormat The data format used for the internal storage of the texture. |
| * @param externalFormat The data format used for the external storage of the texture. |
| * @param externalType The type of the data used for the external storage of the texture. |
| @@ -928,6 +949,7 @@ static inline GrGLenum check_alloc_error(const GrSurfaceDesc& desc, |
| */ |
| static void allocate_and_populate_uncompressed_texture(const GrSurfaceDesc& desc, |
| const GrGLInterface& interface, |
| + bool useTexStorage, |
| GrGLenum target, |
| GrGLenum internalFormat, |
| GrGLenum externalFormat, |
| @@ -936,27 +958,61 @@ static void allocate_and_populate_uncompressed_texture(const GrSurfaceDesc& desc |
| int baseWidth, int baseHeight, |
| bool* succeeded) { |
| CLEAR_ERROR_BEFORE_ALLOC(&interface); |
| - *succeeded = true; |
| - for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
| - int twoToTheMipLevel = 1 << currentMipLevel; |
| - int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel); |
| - int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel); |
| - const void* currentMipData = texels[currentMipLevel].fPixels; |
| - // Even if curremtMipData is nullptr, continue to call TexImage2D. |
| - // This will allocate texture memory which we can later populate. |
| + if (useTexStorage) { |
| + // We never resize or change formats of textures. |
| GL_ALLOC_CALL(&interface, |
| - TexImage2D(target, |
| - currentMipLevel, |
| - internalFormat, |
| - currentWidth, |
| - currentHeight, |
| - 0, // border |
| - externalFormat, externalType, |
| - currentMipData)); |
| + TexStorage2D(target, |
|
bsalomon
2016/02/26 22:09:54
Won't this cause a problem if we later call glGene
cblume
2016/02/27 00:49:54
The calling sites currently only have useTexStorag
|
| + texels.count(), |
| + internalFormat, |
| + desc.fWidth, desc.fHeight)); |
| GrGLenum error = check_alloc_error(desc, &interface); |
| if (error != GR_GL_NO_ERROR) { |
| *succeeded = false; |
| - break; |
| + } else { |
| + for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
| + const void* currentMipData = texels[currentMipLevel].fPixels; |
| + if (currentMipData == nullptr) { |
| + continue; |
| + } |
| + int twoToTheMipLevel = 1 << currentMipLevel; |
| + int currentWidth = SkTMax(1, desc.fWidth / twoToTheMipLevel); |
| + int currentHeight = SkTMax(1, desc.fHeight / twoToTheMipLevel); |
| + |
| + GR_GL_CALL(&interface, |
| + TexSubImage2D(target, |
| + currentMipLevel, |
| + 0, // left |
| + 0, // top |
| + currentWidth, |
| + currentHeight, |
| + externalFormat, externalType, |
| + currentMipData)); |
| + } |
| + *succeeded = true; |
| + } |
| + } else { |
| + *succeeded = true; |
| + for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
| + int twoToTheMipLevel = 1 << currentMipLevel; |
| + int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel); |
| + int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel); |
| + const void* currentMipData = texels[currentMipLevel].fPixels; |
| + // Even if curremtMipData is nullptr, continue to call TexImage2D. |
| + // This will allocate texture memory which we can later populate. |
| + GL_ALLOC_CALL(&interface, |
| + TexImage2D(target, |
| + currentMipLevel, |
| + internalFormat, |
| + currentWidth, |
| + currentHeight, |
| + 0, // border |
| + externalFormat, externalType, |
| + currentMipData)); |
| + GrGLenum error = check_alloc_error(desc, &interface); |
| + if (error != GR_GL_NO_ERROR) { |
| + *succeeded = false; |
| + break; |
| + } |
| } |
| } |
| } |
| @@ -966,40 +1022,77 @@ static void allocate_and_populate_uncompressed_texture(const GrSurfaceDesc& desc |
| * |
| * @param desc The surface descriptor for the texture being created. |
| * @param interface The GL interface in use. |
| - * @param target The GL target to which the texture is bound |
| + * @param useTexStorage The result of a call to can_use_tex_storage(). |
| * @param internalFormat The data format used for the internal storage of the texture. |
| * @param texels The texel data of the texture being created. |
| - * @param baseWidth The width of the texture's base mipmap level |
| - * @param baseHeight The height of the texture's base mipmap level |
| */ |
| static bool allocate_and_populate_compressed_texture(const GrSurfaceDesc& desc, |
| const GrGLInterface& interface, |
| + bool useTexStorage, |
| GrGLenum target, GrGLenum internalFormat, |
| const SkTArray<GrMipLevel>& texels, |
| int baseWidth, int baseHeight) { |
| CLEAR_ERROR_BEFORE_ALLOC(&interface); |
| - for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
| - int twoToTheMipLevel = 1 << currentMipLevel; |
| - int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel); |
| - int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel); |
| - |
| - // Make sure that the width and height that we pass to OpenGL |
| - // is a multiple of the block size. |
| - size_t dataSize = GrCompressedFormatDataSize(desc.fConfig, baseWidth, baseHeight); |
| - |
| + if (useTexStorage) { |
| + // We never resize or change formats of textures. |
| GL_ALLOC_CALL(&interface, |
| - CompressedTexImage2D(target, |
| - currentMipLevel, |
| - internalFormat, |
| - currentWidth, |
| - currentHeight, |
| - 0, // border |
| - SkToInt(dataSize), |
| - texels[currentMipLevel].fPixels)); |
| - |
| + TexStorage2D(target, |
| + texels.count(), |
| + internalFormat, |
| + baseWidth, baseHeight)); |
| GrGLenum error = check_alloc_error(desc, &interface); |
| if (error != GR_GL_NO_ERROR) { |
| return false; |
| + } else { |
| + for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
| + const void* currentMipData = texels[currentMipLevel].fPixels; |
| + if (currentMipData == nullptr) { |
| + continue; |
| + } |
| + |
| + int twoToTheMipLevel = 1 << currentMipLevel; |
| + int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel); |
| + int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel); |
| + |
| + // Make sure that the width and height that we pass to OpenGL |
| + // is a multiple of the block size. |
| + size_t dataSize = GrCompressedFormatDataSize(desc.fConfig, currentWidth, |
| + currentHeight); |
| + GR_GL_CALL(&interface, CompressedTexSubImage2D(target, |
| + currentMipLevel, |
| + 0, // left |
| + 0, // top |
| + currentWidth, |
| + currentHeight, |
| + internalFormat, |
| + SkToInt(dataSize), |
| + currentMipData)); |
| + } |
| + } |
| + } else { |
| + for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
| + int twoToTheMipLevel = 1 << currentMipLevel; |
| + int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel); |
| + int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel); |
| + |
| + // Make sure that the width and height that we pass to OpenGL |
| + // is a multiple of the block size. |
| + size_t dataSize = GrCompressedFormatDataSize(desc.fConfig, baseWidth, baseHeight); |
| + |
| + GL_ALLOC_CALL(&interface, |
| + CompressedTexImage2D(target, |
| + currentMipLevel, |
| + internalFormat, |
| + currentWidth, |
| + currentHeight, |
| + 0, // border |
| + SkToInt(dataSize), |
| + texels[currentMipLevel].fPixels)); |
| + |
| + GrGLenum error = check_alloc_error(desc, &interface); |
| + if (error != GR_GL_NO_ERROR) { |
| + return false; |
| + } |
| } |
| } |
| @@ -1052,6 +1145,7 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, |
| const GrGLInterface* interface = this->glInterface(); |
| const GrGLCaps& caps = this->glCaps(); |
| + GrGLStandard standard = this->glStandard(); |
| size_t bpp = GrBytesPerPixel(dataConfig); |
| @@ -1191,7 +1285,14 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, |
| 0 == left && 0 == top && |
| desc.fWidth == width && desc.fHeight == height && |
| !desc.fTextureStorageAllocator.fAllocateTextureStorage) { |
| - allocate_and_populate_uncompressed_texture(desc, *interface, target, |
| + bool useTexStorage = can_use_tex_storage(caps, standard, desc); |
| + // We can only use TexStorage if we know we will not later change the storage requirements. |
| + // This means if we may later want to generate mipmaps, we cannot use TexStorage. |
| + // Right now, we cannot know if we will later generate mipmaps or not. |
| + // The only time we can use TexStorage is when we already have the |
| + // mipmaps. |
| + useTexStorage &= texelsShallowCopy.count() > 1; |
| + allocate_and_populate_uncompressed_texture(desc, *interface, useTexStorage, target, |
| internalFormat, externalFormat, |
| externalType, texelsShallowCopy, |
| width, height, &succeeded); |
| @@ -1242,6 +1343,7 @@ bool GrGLGpu::uploadCompressedTexData(const GrSurfaceDesc& desc, |
| const GrGLInterface* interface = this->glInterface(); |
| const GrGLCaps& caps = this->glCaps(); |
| + GrGLStandard standard = this->glStandard(); |
| if (-1 == width) { |
| width = desc.fWidth; |
| @@ -1268,8 +1370,15 @@ bool GrGLGpu::uploadCompressedTexData(const GrSurfaceDesc& desc, |
| } |
| if (kNewTexture_UploadType == uploadType) { |
| - return allocate_and_populate_compressed_texture(desc, *interface, target, internalFormat, |
| - texels, width, height); |
| + bool useTexStorage = can_use_tex_storage(caps, standard, desc); |
| + // We can only use TexStorage if we know we will not later change the storage requirements. |
| + // This means if we may later want to generate mipmaps, we cannot use TexStorage. |
| + // Right now, we cannot know if we will later generate mipmaps or not. |
| + // The only time we can use TexStorage is when we already have the |
| + // mipmaps. |
| + useTexStorage &= texels.count() > 1; |
| + return allocate_and_populate_compressed_texture(desc, *interface, useTexStorage, target, |
| + internalFormat, texels, width, height); |
| } else { |
| // Paletted textures can't be updated. |
| if (GR_GL_PALETTE8_RGBA8 == internalFormat) { |