Index: src/gpu/gl/GrGLGpu.cpp |
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp |
index 5c03ab57d28a1b52cf0bb7463d7c2498ba8de64c..bb4821db62ba7dae42962485c529cd272b01f8c2 100644 |
--- a/src/gpu/gl/GrGLGpu.cpp |
+++ b/src/gpu/gl/GrGLGpu.cpp |
@@ -473,7 +473,7 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, |
GrSurfaceDesc surfDesc; |
idDesc.fTextureID = static_cast<GrGLuint>(desc.fTextureHandle); |
- |
+ |
switch (ownership) { |
case kAdopt_GrWrapOwnership: |
idDesc.fLifeCycle = GrGpuResource::kAdopted_LifeCycle; |
@@ -481,7 +481,7 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, |
case kBorrow_GrWrapOwnership: |
idDesc.fLifeCycle = GrGpuResource::kBorrowed_LifeCycle; |
break; |
- } |
+ } |
// next line relies on GrBackendTextureDesc's flags matching GrTexture's |
surfDesc.fFlags = (GrSurfaceFlags) desc.fFlags; |
@@ -531,7 +531,7 @@ GrRenderTarget* GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDe |
case kBorrow_GrWrapOwnership: |
idDesc.fLifeCycle = GrGpuResource::kBorrowed_LifeCycle; |
break; |
- } |
+ } |
idDesc.fSampleConfig = GrRenderTarget::kUnified_SampleConfig; |
GrSurfaceDesc desc; |
@@ -631,36 +631,10 @@ static inline GrGLenum check_alloc_error(const GrSurfaceDesc& desc, |
} |
} |
-bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, |
- bool isNewTexture, |
- int left, int top, int width, int height, |
- GrPixelConfig dataConfig, |
- const void* data, |
- size_t rowBytes) { |
- SkASSERT(data || isNewTexture); |
- |
- // If we're uploading compressed data then we should be using uploadCompressedTexData |
- SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); |
- |
- size_t bpp = GrBytesPerPixel(dataConfig); |
- if (!adjust_pixel_ops_params(desc.fWidth, desc.fHeight, bpp, &left, &top, |
- &width, &height, &data, &rowBytes)) { |
- return false; |
- } |
- size_t trimRowBytes = width * bpp; |
- |
- // in case we need a temporary, trimmed copy of the src pixels |
- SkAutoSMalloc<128 * 128> tempStorage; |
- |
- // We currently lazily create MIPMAPs when the we see a draw with |
- // GrTextureParams::kMipMap_FilterMode. Using texture storage requires that the |
- // MIP levels are all created when the texture is created. So for now we don't use |
- // texture storage. |
- bool useTexStorage = false && |
- isNewTexture && |
- this->glCaps().texStorageSupport(); |
- |
- if (useTexStorage && kGL_GrGLStandard == this->glStandard()) { |
+static bool can_use_tex_storage(const GrGLCaps& caps, const GrGLStandard& standard, |
+ const GrSurfaceDesc& desc) { |
+ bool useTexStorage = caps.texStorageSupport(); |
+ if (useTexStorage && kGL_GrGLStandard == standard) { |
// 565 is not a sized internal format on desktop GL. So on desktop with |
// 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 |
@@ -668,114 +642,245 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, |
useTexStorage = desc.fConfig != kRGB_565_GrPixelConfig; |
} |
- GrGLenum internalFormat = 0x0; // suppress warning |
- GrGLenum externalFormat = 0x0; // suppress warning |
- GrGLenum externalType = 0x0; // suppress warning |
+ return useTexStorage; |
+} |
+static bool can_use_sized_format(bool useTexStorage, const GrGLCaps& caps, |
+ const GrGLStandard& standard, const GrGLVersion& version, |
+ GrPixelConfig dataConfig) { |
// glTexStorage requires sized internal formats on both desktop and ES. ES2 requires an unsized |
// format for glTexImage, unlike ES3 and desktop. |
bool useSizedFormat = useTexStorage; |
- if (kGL_GrGLStandard == this->glStandard() || |
- (this->glVersion() >= GR_GL_VER(3, 0) && |
+ if (kGL_GrGLStandard == standard || |
+ (version >= GR_GL_VER(3, 0) && |
// ES3 only works with sized BGRA8 format if "GL_APPLE_texture_format_BGRA8888" enabled |
- (kBGRA_8888_GrPixelConfig != dataConfig || !this->glCaps().bgraIsInternalFormat()))) { |
+ (kBGRA_8888_GrPixelConfig != dataConfig || !caps.bgraIsInternalFormat()))) { |
useSizedFormat = true; |
} |
- if (!this->configToGLFormats(dataConfig, useSizedFormat, &internalFormat, |
- &externalFormat, &externalType)) { |
- return false; |
+ return useSizedFormat; |
+} |
+ |
+static void prepare_image_for_writing_to_texture(const GrSurfaceDesc& desc, const GrGLCaps& caps, |
+ bool swFlipY, bool glFlipY, int width, int height, |
+ int bpp, size_t rowBytes, const void*& data, |
+ SkAutoSMalloc<128 * 128>& tempStorage, |
+ const GrGLInterface* interface, |
+ bool& restoreGLRowLength) { |
+ if (NULL == interface) { |
+ return; |
} |
+ size_t trimRowBytes = width * bpp; |
+ |
/* |
* check whether to allocate a temporary buffer for flipping y or |
* because our srcData has extra bytes past each row. If so, we need |
* to trim those off here, since GL ES may not let us specify |
* GL_UNPACK_ROW_LENGTH. |
*/ |
- bool restoreGLRowLength = false; |
- bool swFlipY = false; |
- bool glFlipY = false; |
- if (data) { |
- if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { |
- if (this->glCaps().unpackFlipYSupport()) { |
- glFlipY = true; |
- } else { |
- swFlipY = true; |
- } |
+ restoreGLRowLength = false; |
+ |
+ if (caps.unpackRowLengthSupport() && !swFlipY) { |
+ // can't use this for flipping, only non-neg values allowed. :( |
+ if (rowBytes != trimRowBytes) { |
+ GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp); |
+ GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength)); |
+ restoreGLRowLength = true; |
} |
- if (this->glCaps().unpackRowLengthSupport() && !swFlipY) { |
- // can't use this for flipping, only non-neg values allowed. :( |
- if (rowBytes != trimRowBytes) { |
- GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp); |
- GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength)); |
- restoreGLRowLength = true; |
+ } else { |
+ if (trimRowBytes != rowBytes || swFlipY) { |
+ // copy data into our new storage, skipping the trailing bytes |
+ size_t trimSize = height * trimRowBytes; |
+ const char* src = (const char*)data; |
+ if (swFlipY) { |
+ src += (height - 1) * rowBytes; |
} |
- } else { |
- if (trimRowBytes != rowBytes || swFlipY) { |
- // copy data into our new storage, skipping the trailing bytes |
- size_t trimSize = height * trimRowBytes; |
- const char* src = (const char*)data; |
+ char* dst = (char*)tempStorage.reset(trimSize); |
+ for (int y = 0; y < height; y++) { |
+ memcpy(dst, src, trimRowBytes); |
if (swFlipY) { |
- src += (height - 1) * rowBytes; |
- } |
- char* dst = (char*)tempStorage.reset(trimSize); |
- for (int y = 0; y < height; y++) { |
- memcpy(dst, src, trimRowBytes); |
- if (swFlipY) { |
- src -= rowBytes; |
- } else { |
- src += rowBytes; |
- } |
- dst += trimRowBytes; |
+ src -= rowBytes; |
+ } else { |
+ src += rowBytes; |
} |
- // now point data to our copied version |
- data = tempStorage.get(); |
+ dst += trimRowBytes; |
} |
+ // now point data to our copied version |
+ data = tempStorage.get(); |
} |
- if (glFlipY) { |
- GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_TRUE)); |
- } |
- GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, |
- static_cast<GrGLint>(GrUnpackAlignment(dataConfig)))); |
} |
- bool succeeded = true; |
- if (isNewTexture && |
- 0 == left && 0 == top && |
- desc.fWidth == width && desc.fHeight == height) { |
- CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); |
- if (useTexStorage) { |
- // We never resize or change formats of textures. |
- GL_ALLOC_CALL(this->glInterface(), |
- TexStorage2D(GR_GL_TEXTURE_2D, |
- 1, // levels |
- internalFormat, |
- desc.fWidth, desc.fHeight)); |
- } else { |
- GL_ALLOC_CALL(this->glInterface(), |
+ if (glFlipY) { |
+ GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_TRUE)); |
+ } |
+ GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ALIGNMENT, |
+ static_cast<GrGLint>(GrUnpackAlignment(desc.fConfig)))); |
+} |
+ |
+static void allocate_and_populate_uncompressed_texture(const GrGLInterface* interface, |
+ bool useTexStorage, |
+ GrGLenum internalFormat, |
+ GrGLenum externalFormat, |
+ GrGLenum externalType, |
+ const GrSurfaceDesc& desc, |
+ SkTArray<const void*>& data, |
+ bool& succeeded) { |
+ CLEAR_ERROR_BEFORE_ALLOC(interface); |
+ if (useTexStorage) { |
+ // We never resize or change formats of textures. |
+ GL_ALLOC_CALL(interface, |
+ TexStorage2D(GR_GL_TEXTURE_2D, |
+ data.count(), |
+ internalFormat, |
+ desc.fWidth, desc.fHeight)); |
+ } else { |
+ int width = desc.fWidth; |
+ int height = desc.fHeight; |
+ for (int currentMipLevel = 0; currentMipLevel < data.count(); currentMipLevel++) { |
+ GL_ALLOC_CALL(interface, |
TexImage2D(GR_GL_TEXTURE_2D, |
- 0, // level |
+ currentMipLevel, |
internalFormat, |
- desc.fWidth, desc.fHeight, |
+ width, height, |
0, // border |
externalFormat, externalType, |
- data)); |
+ data[currentMipLevel])); |
+ width /= 2; |
+ height /= 2; |
} |
- GrGLenum error = check_alloc_error(desc, this->glInterface()); |
- if (error != GR_GL_NO_ERROR) { |
- succeeded = false; |
+ } |
+ |
+ GrGLenum error = check_alloc_error(desc, interface); |
+ if (error != GR_GL_NO_ERROR) { |
+ succeeded = false; |
+ } else { |
+ int width = desc.fWidth; |
+ int height = desc.fHeight; |
+ for (int currentMipLevel = data.count(); currentMipLevel != 0; currentMipLevel--) { |
+ auto currentMipData = data[currentMipLevel]; |
+ GR_GL_CALL(interface, |
+ TexSubImage2D(GR_GL_TEXTURE_2D, |
+ currentMipLevel, |
+ 0, // left |
+ 0, // top |
+ width, height, |
+ externalFormat, externalType, |
+ currentMipData)); |
+ width /= 2; |
+ height /= 2; |
+ } |
+ } |
+} |
+ |
+static bool allocate_and_populate_compressed_texture(const GrGLInterface* interface, |
+ bool useTexStorage, GrGLenum internalFormat, |
+ const GrSurfaceDesc& desc, |
+ SkTArray<const void*>& data, |
+ size_t dataSize) { |
+ CLEAR_ERROR_BEFORE_ALLOC(interface); |
+ if (useTexStorage) { |
+ // We never resize or change formats of textures. |
+ GL_ALLOC_CALL(interface, |
+ TexStorage2D(GR_GL_TEXTURE_2D, |
+ data.count(), |
+ internalFormat, |
+ desc.fWidth, desc.fHeight)); |
+ } else { |
+ int width = desc.fWidth; |
+ int height = desc.fHeight; |
+ for (int currentMipLevel = 0; currentMipLevel < data.count(); currentMipLevel++) { |
+ GL_ALLOC_CALL(interface, |
+ CompressedTexImage2D(GR_GL_TEXTURE_2D, |
+ data.count(), |
+ internalFormat, |
+ width, height, |
+ 0, // border |
+ SkToInt(dataSize), |
+ data[currentMipLevel])); |
+ width /= 2; |
+ height /= 2; |
+ } |
+ } |
+ |
+ GrGLenum error = check_alloc_error(desc, interface); |
+ if (error != GR_GL_NO_ERROR) { |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+static void restore_gl_state(bool restoreGLRowLength, const GrGLInterface* interface, |
+ const GrGLCaps& caps, bool glFlipY) { |
+ if (restoreGLRowLength) { |
+ SkASSERT(caps.unpackRowLengthSupport()); |
+ GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0)); |
+ } |
+ if (glFlipY) { |
+ GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_FALSE)); |
+ } |
+} |
+ |
+bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, |
+ bool isNewTexture, |
+ int left, int top, int width, int height, |
+ GrPixelConfig dataConfig, |
+ const void* data, |
+ size_t rowBytes) { |
+ SkASSERT(data || isNewTexture); |
+ |
+ // If we're uploading compressed data then we should be using uploadCompressedTexData |
+ SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); |
+ |
+ size_t bpp = GrBytesPerPixel(dataConfig); |
+ if (!adjust_pixel_ops_params(desc.fWidth, desc.fHeight, bpp, &left, &top, |
+ &width, &height, &data, &rowBytes)) { |
+ return false; |
+ } |
+ |
+ bool useTexStorage = can_use_tex_storage(this->glCaps(), this->glStandard(), |
+ desc); |
+ bool useSizedFormat = can_use_sized_format(useTexStorage, this->glCaps(), this->glStandard(), |
+ this->glVersion(), dataConfig); |
+ |
+ GrGLenum internalFormat = 0x0; // suppress warning |
+ GrGLenum externalFormat = 0x0; // suppress warning |
+ GrGLenum externalType = 0x0; // suppress warning |
+ |
+ if (!this->configToGLFormats(dataConfig, useSizedFormat, &internalFormat, |
+ &externalFormat, &externalType)) { |
+ return false; |
+ } |
+ |
+ bool swFlipY = false; |
+ bool glFlipY = false; |
+ |
+ if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { |
+ if (glCaps().unpackFlipYSupport()) { |
+ glFlipY = true; |
} else { |
- // if we have data and we used TexStorage to create the texture, we |
- // now upload with TexSubImage. |
- if (data && useTexStorage) { |
- GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D, |
- 0, // level |
- left, top, |
- width, height, |
- externalFormat, externalType, |
- data)); |
- } |
+ swFlipY = true; |
} |
+ } |
+ |
+ bool restoreGLRowLength = false; |
+ |
+ // in case we need a temporary, trimmed copy of the src pixels |
+ SkAutoSMalloc<128 * 128> tempStorage; |
+ if (data) { |
+ prepare_image_for_writing_to_texture(desc, this->glCaps(), swFlipY, glFlipY, width, height, |
+ bpp, rowBytes, data, tempStorage, this->glInterface(), |
+ restoreGLRowLength); |
+ } |
+ bool succeeded = true; |
+ if (isNewTexture && |
+ 0 == left && 0 == top && |
+ desc.fWidth == width && desc.fHeight == height) { |
+ const int mipLevelCount = 1; |
+ SkTArray<const void*> mipLevels(mipLevelCount); |
+ mipLevels[0] = data; |
+ allocate_and_populate_uncompressed_texture(this->glInterface(), useTexStorage, |
+ internalFormat, externalFormat, externalType, |
+ desc, mipLevels, succeeded); |
} else { |
if (swFlipY || glFlipY) { |
top = desc.fHeight - (top + height); |
@@ -787,13 +892,8 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, |
externalFormat, externalType, data)); |
} |
- if (restoreGLRowLength) { |
- SkASSERT(this->glCaps().unpackRowLengthSupport()); |
- GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0)); |
- } |
- if (glFlipY) { |
- GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_FALSE)); |
- } |
+ restore_gl_state(restoreGLRowLength, this->glInterface(), this->glCaps(), glFlipY); |
+ |
return succeeded; |
} |
@@ -829,6 +929,9 @@ bool GrGLGpu::uploadCompressedTexData(const GrSurfaceDesc& desc, |
} |
#endif |
+ bool useTexStorage = can_use_tex_storage(this->glCaps(), this->glStandard(), |
+ desc); |
+ |
// 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, width, height); |
@@ -840,19 +943,11 @@ bool GrGLGpu::uploadCompressedTexData(const GrSurfaceDesc& desc, |
} |
if (isNewTexture) { |
- CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); |
- GL_ALLOC_CALL(this->glInterface(), |
- CompressedTexImage2D(GR_GL_TEXTURE_2D, |
- 0, // level |
- internalFormat, |
- width, height, |
- 0, // border |
- SkToInt(dataSize), |
- data)); |
- GrGLenum error = check_alloc_error(desc, this->glInterface()); |
- if (error != GR_GL_NO_ERROR) { |
- return false; |
- } |
+ const int mipLevelCount = 1; |
+ SkTArray<const void*> mipLevels(mipLevelCount); |
+ mipLevels[0] = data; |
+ return allocate_and_populate_compressed_texture(this->glInterface(), useTexStorage, |
+ internalFormat, desc, mipLevels, dataSize); |
} else { |
// Paletted textures can't be updated. |
if (GR_GL_PALETTE8_RGBA8 == internalFormat) { |
@@ -870,6 +965,99 @@ bool GrGLGpu::uploadCompressedTexData(const GrSurfaceDesc& desc, |
return true; |
} |
+bool GrGLGpu::uploadMipmappedTexData(const GrSurfaceDesc& desc, |
+ const SkMipMap& data) { |
+ // If we're uploading compressed data then we should be using uploadCompressedMipmappedTexData |
+ SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig)); |
+ |
+ size_t bpp = GrBytesPerPixel(desc.fConfig); |
+ |
+ bool useTexStorage = can_use_tex_storage(this->glCaps(), this->glStandard(), |
+ desc); |
+ bool useSizedFormat = can_use_sized_format(useTexStorage, this->glCaps(), this->glStandard(), |
+ this->glVersion(), desc.fConfig); |
+ |
+ GrGLenum internalFormat = 0x0; // suppress warning |
+ GrGLenum externalFormat = 0x0; // suppress warning |
+ GrGLenum externalType = 0x0; // suppress warning |
+ |
+ if (!this->configToGLFormats(desc.fConfig, useSizedFormat, &internalFormat, |
+ &externalFormat, &externalType)) { |
+ return false; |
+ } |
+ |
+ bool swFlipY = false; |
+ bool glFlipY = false; |
+ |
+ if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { |
+ if (glCaps().unpackFlipYSupport()) { |
+ glFlipY = true; |
+ } else { |
+ swFlipY = true; |
+ } |
+ } |
+ |
+ bool restoreGLRowLength = false; |
+ |
+ // in case we need a temporary, trimmed copy of the src pixels |
+ SkAutoSMalloc<128 * 128> tempStorage; |
+ |
+ bool succeeded = true; |
+ auto mipLevelCount = data.getLevelsCount(); |
+ SkTArray<const void*> mipLevels(mipLevelCount); |
+ for (int currentMipLevel = mipLevelCount; currentMipLevel != 0; currentMipLevel--) { |
+ SkMipMap::Level currentMipData; |
+ if (data.getLevel(currentMipLevel, ¤tMipData)) { |
+ mipLevels[currentMipLevel] = currentMipData.fPixels; |
+ |
+ prepare_image_for_writing_to_texture(desc, this->glCaps(), swFlipY, glFlipY, |
+ currentMipData.fWidth, currentMipData.fHeight, |
+ bpp, currentMipData.fRowBytes, |
+ mipLevels[currentMipLevel], tempStorage, |
+ this->glInterface(), restoreGLRowLength); |
+ } |
+ } |
+ allocate_and_populate_uncompressed_texture(this->glInterface(), useTexStorage, internalFormat, |
+ externalFormat, externalType, desc, mipLevels, |
+ succeeded); |
+ |
+ restore_gl_state(restoreGLRowLength, this->glInterface(), this->glCaps(), glFlipY); |
+ |
+ return succeeded; |
+} |
+ |
+bool GrGLGpu::uploadCompressedMipmappedTexData(const GrSurfaceDesc& desc, |
+ const SkMipMap& data) { |
+ // No support for software flip y, yet... |
+ SkASSERT(kBottomLeft_GrSurfaceOrigin != desc.fOrigin); |
+ |
+ // 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, desc.fWidth, desc.fHeight); |
+ |
+ bool useTexStorage = can_use_tex_storage(this->glCaps(), this->glStandard(), |
+ desc); |
+ bool useSizedFormat = can_use_sized_format(useTexStorage, this->glCaps(), this->glStandard(), |
+ this->glVersion(), desc.fConfig); |
+ |
+ // We only need the internal format for compressed 2D textures. |
+ GrGLenum internalFormat = 0; |
+ if (!this->configToGLFormats(desc.fConfig, false, &internalFormat, NULL, NULL)) { |
+ return false; |
+ } |
+ |
+ auto mipLevelCount = data.getLevelsCount(); |
+ SkTArray<const void*> mipLevels(mipLevelCount); |
+ for (int currentLevelIndex = mipLevelCount; currentLevelIndex != 0; currentLevelIndex--) { |
+ SkMipMap::Level currentLevel; |
+ if (data.getLevel(currentLevelIndex, ¤tLevel)) { |
+ mipLevels[currentLevelIndex] = currentLevel.fPixels; |
+ } |
+ } |
+ return allocate_and_populate_compressed_texture(this->glInterface(), useTexStorage, |
+ internalFormat, desc, mipLevels, dataSize); |
+} |
+ |
static bool renderbuffer_storage_msaa(const GrGLContext& ctx, |
int sampleCount, |
GrGLenum format, |
@@ -1032,6 +1220,40 @@ static size_t as_size_t(int x) { |
} |
#endif |
+static GrGLTexture::IDDesc generate_and_bind_gl_texture(const GrGLInterface* interface, |
+ GrGpuResource::LifeCycle lifeCycle) { |
+ GrGLTexture::IDDesc idDesc; |
+ GR_GL_CALL(interface, GenTextures(1, &idDesc.fTextureID)); |
+ idDesc.fLifeCycle = lifeCycle; |
+ return idDesc; |
+} |
+ |
+static GrGLTexture::TexParams set_initial_texture_params(const GrGLInterface* interface) { |
+ // Some drivers like to know filter/wrap before seeing glTexImage2D. Some |
+ // drivers have a bug where an FBO won't be complete if it includes a |
+ // texture that is not mipmap complete (considering the filter in use). |
+ GrGLTexture::TexParams initialTexParams; |
+ // we only set a subset here so invalidate first |
+ initialTexParams.invalidate(); |
+ initialTexParams.fMinFilter = GR_GL_NEAREST; |
+ initialTexParams.fMagFilter = GR_GL_NEAREST; |
+ initialTexParams.fWrapS = GR_GL_CLAMP_TO_EDGE; |
+ initialTexParams.fWrapT = GR_GL_CLAMP_TO_EDGE; |
+ GR_GL_CALL(interface, TexParameteri(GR_GL_TEXTURE_2D, |
+ GR_GL_TEXTURE_MAG_FILTER, |
+ initialTexParams.fMagFilter)); |
+ GR_GL_CALL(interface, TexParameteri(GR_GL_TEXTURE_2D, |
+ GR_GL_TEXTURE_MIN_FILTER, |
+ initialTexParams.fMinFilter)); |
+ GR_GL_CALL(interface, TexParameteri(GR_GL_TEXTURE_2D, |
+ GR_GL_TEXTURE_WRAP_S, |
+ initialTexParams.fWrapS)); |
+ GR_GL_CALL(interface, TexParameteri(GR_GL_TEXTURE_2D, |
+ GR_GL_TEXTURE_WRAP_T, |
+ initialTexParams.fWrapT)); |
+ return initialTexParams; |
+} |
+ |
GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, |
GrGpuResource::LifeCycle lifeCycle, |
const void* srcData, size_t rowBytes) { |
@@ -1043,10 +1265,7 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, |
bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); |
- GrGLTexture::IDDesc idDesc; |
- GL_CALL(GenTextures(1, &idDesc.fTextureID)); |
- idDesc.fLifeCycle = lifeCycle; |
- |
+ auto idDesc = generate_and_bind_gl_texture(this->glInterface(), lifeCycle); |
if (!idDesc.fTextureID) { |
return return_null_texture(); |
} |
@@ -1061,28 +1280,8 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, |
GR_GL_FRAMEBUFFER_ATTACHMENT)); |
} |
- // Some drivers like to know filter/wrap before seeing glTexImage2D. Some |
- // drivers have a bug where an FBO won't be complete if it includes a |
- // texture that is not mipmap complete (considering the filter in use). |
- GrGLTexture::TexParams initialTexParams; |
- // we only set a subset here so invalidate first |
- initialTexParams.invalidate(); |
- initialTexParams.fMinFilter = GR_GL_NEAREST; |
- initialTexParams.fMagFilter = GR_GL_NEAREST; |
- initialTexParams.fWrapS = GR_GL_CLAMP_TO_EDGE; |
- initialTexParams.fWrapT = GR_GL_CLAMP_TO_EDGE; |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_MAG_FILTER, |
- initialTexParams.fMagFilter)); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_MIN_FILTER, |
- initialTexParams.fMinFilter)); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_WRAP_S, |
- initialTexParams.fWrapS)); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_WRAP_T, |
- initialTexParams.fWrapT)); |
+ auto initialTexParams = set_initial_texture_params(this->glInterface()); |
+ |
if (!this->uploadTexData(desc, true, 0, 0, |
desc.fWidth, desc.fHeight, |
desc.fConfig, srcData, rowBytes)) { |
@@ -1120,10 +1319,7 @@ GrTexture* GrGLGpu::onCreateCompressedTexture(const GrSurfaceDesc& desc, |
return return_null_texture(); |
} |
- GrGLTexture::IDDesc idDesc; |
- GL_CALL(GenTextures(1, &idDesc.fTextureID)); |
- idDesc.fLifeCycle = lifeCycle; |
- |
+ auto idDesc = generate_and_bind_gl_texture(this->glInterface(), lifeCycle); |
if (!idDesc.fTextureID) { |
return return_null_texture(); |
} |
@@ -1131,28 +1327,7 @@ GrTexture* GrGLGpu::onCreateCompressedTexture(const GrSurfaceDesc& desc, |
this->setScratchTextureUnit(); |
GL_CALL(BindTexture(GR_GL_TEXTURE_2D, idDesc.fTextureID)); |
- // Some drivers like to know filter/wrap before seeing glTexImage2D. Some |
- // drivers have a bug where an FBO won't be complete if it includes a |
- // texture that is not mipmap complete (considering the filter in use). |
- GrGLTexture::TexParams initialTexParams; |
- // we only set a subset here so invalidate first |
- initialTexParams.invalidate(); |
- initialTexParams.fMinFilter = GR_GL_NEAREST; |
- initialTexParams.fMagFilter = GR_GL_NEAREST; |
- initialTexParams.fWrapS = GR_GL_CLAMP_TO_EDGE; |
- initialTexParams.fWrapT = GR_GL_CLAMP_TO_EDGE; |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_MAG_FILTER, |
- initialTexParams.fMagFilter)); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_MIN_FILTER, |
- initialTexParams.fMinFilter)); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_WRAP_S, |
- initialTexParams.fWrapS)); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_WRAP_T, |
- initialTexParams.fWrapT)); |
+ auto initialTexParams = set_initial_texture_params(this->glInterface()); |
if (!this->uploadCompressedTexData(desc, srcData)) { |
GL_CALL(DeleteTextures(1, &idDesc.fTextureID)); |
@@ -1169,6 +1344,93 @@ GrTexture* GrGLGpu::onCreateCompressedTexture(const GrSurfaceDesc& desc, |
return tex; |
} |
+GrTexture* GrGLGpu::onCreateMipmappedTexture(const GrSurfaceDesc& desc, |
+ GrGpuResource::LifeCycle lifeCycle, |
+ const SkMipMap& srcData) |
+{ |
+ // We fail if the MSAA was requested and is not available. |
+ if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType() && desc.fSampleCnt) { |
+ //SkDebugf("MSAA RT requested but not supported on this platform."); |
+ return return_null_texture(); |
+ } |
+ |
+ bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); |
+ |
+ auto idDesc = generate_and_bind_gl_texture(this->glInterface(), lifeCycle); |
+ if (!idDesc.fTextureID) { |
+ return return_null_texture(); |
+ } |
+ |
+ if (renderTarget && this->glCaps().textureUsageSupport()) { |
+ // provides a hint about how this texture will be used |
+ GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
+ GR_GL_TEXTURE_USAGE, |
+ GR_GL_FRAMEBUFFER_ATTACHMENT)); |
+ } |
+ |
+ auto initialTexParams = set_initial_texture_params(this->glInterface()); |
+ |
+ if (!this->uploadMipmappedTexData(desc, srcData)) { |
+ GL_CALL(DeleteTextures(1, &idDesc.fTextureID)); |
+ return return_null_texture(); |
+ } |
+ |
+ GrGLTexture* tex; |
+ if (renderTarget) { |
+ // unbind the texture from the texture unit before binding it to the frame buffer |
+ GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0)); |
+ GrGLRenderTarget::IDDesc rtIDDesc; |
+ |
+ if (!this->createRenderTargetObjects(desc, lifeCycle, idDesc.fTextureID, &rtIDDesc)) { |
+ GL_CALL(DeleteTextures(1, &idDesc.fTextureID)); |
+ return return_null_texture(); |
+ } |
+ tex = SkNEW_ARGS(GrGLTextureRenderTarget, (this, desc, idDesc, rtIDDesc)); |
+ } else { |
+ tex = SkNEW_ARGS(GrGLTexture, (this, desc, idDesc)); |
+ } |
+ tex->setCachedTexParams(initialTexParams, this->getResetTimestamp()); |
+#ifdef TRACE_TEXTURE_CREATION |
+ SkDebugf("--- new mipmapped texture [%d] size=(%d %d) config=%d\n", |
+ glTexDesc.fTextureID, desc.fWidth, desc.fHeight, desc.fConfig); |
+#endif |
+ return tex; |
+} |
+ |
+GrTexture* GrGLGpu::onCreateCompressedMipmappedTexture(const GrSurfaceDesc& desc, |
+ GrGpuResource::LifeCycle lifeCycle, |
+ const SkMipMap& srcData) |
+{ |
+ // Make sure that we're not flipping Y. |
+ if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { |
+ return return_null_texture(); |
+ } |
+ |
+ auto idDesc = generate_and_bind_gl_texture(this->glInterface(), lifeCycle); |
+ if (!idDesc.fTextureID) { |
+ return return_null_texture(); |
+ } |
+ |
+ this->setScratchTextureUnit(); |
+ GL_CALL(BindTexture(GR_GL_TEXTURE_2D, idDesc.fTextureID)); |
+ |
+ auto initialTexParams = set_initial_texture_params(this->glInterface()); |
+ |
+ if (!this->uploadCompressedMipmappedTexData(desc, srcData)) { |
+ GL_CALL(DeleteTextures(1, &idDesc.fTextureID)); |
+ return return_null_texture(); |
+ } |
+ |
+ GrGLTexture* tex; |
+ tex = SkNEW_ARGS(GrGLTexture, (this, desc, idDesc)); |
+ tex->setCachedTexParams(initialTexParams, this->getResetTimestamp()); |
+#ifdef TRACE_TEXTURE_CREATION |
+ SkDebugf("--- new compressed mipmapped texture [%d] size=(%d %d) config=%d\n", |
+ glTexDesc.fTextureID, desc.fWidth, desc.fHeight, desc.fConfig); |
+#endif |
+ return tex; |
+} |
+ |
namespace { |
const GrGLuint kUnknownBitCount = GrGLStencilAttachment::kUnknownBitCount; |