Index: src/gpu/gl/GrGLGpu.cpp |
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp |
index cb12fefc3291f48388275702a71e48d555ddd408..83785e2117b85f17dbef22041657bb302bca4b3f 100644 |
--- a/src/gpu/gl/GrGLGpu.cpp |
+++ b/src/gpu/gl/GrGLGpu.cpp |
@@ -5,7 +5,6 @@ |
* found in the LICENSE file. |
*/ |
- |
#include "GrGLGpu.h" |
#include "GrGLGLSL.h" |
#include "GrGLStencilAttachment.h" |
@@ -21,6 +20,7 @@ |
#include "glsl/GrGLSLCaps.h" |
#include "SkStrokeRec.h" |
#include "SkTemplates.h" |
+#include "SkTypes.h" |
#define GL_CALL(X) GR_GL_CALL(this->glInterface(), X) |
#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glInterface(), RET, X) |
@@ -426,7 +426,9 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, |
GrSurfaceDesc surfDesc; |
idDesc.fTextureID = static_cast<GrGLuint>(desc.fTextureHandle); |
- |
+ // We only support GL_TEXTURE_2D at the moment. |
+ idDesc.fTarget = GR_GL_TEXTURE_2D; |
+ |
switch (ownership) { |
case kAdopt_GrWrapOwnership: |
idDesc.fLifeCycle = GrGpuResource::kAdopted_LifeCycle; |
@@ -434,7 +436,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; |
@@ -457,7 +459,7 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, |
if (renderTarget) { |
GrGLRenderTarget::IDDesc rtIDDesc; |
if (!this->createRenderTargetObjects(surfDesc, GrGpuResource::kUncached_LifeCycle, |
- idDesc.fTextureID, &rtIDDesc)) { |
+ idDesc.fTextureID, idDesc.fTarget, &rtIDDesc)) { |
return nullptr; |
} |
texture = new GrGLTextureRenderTarget(this, surfDesc, idDesc, rtIDDesc); |
@@ -484,7 +486,7 @@ GrRenderTarget* GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDe |
case kBorrow_GrWrapOwnership: |
idDesc.fLifeCycle = GrGpuResource::kBorrowed_LifeCycle; |
break; |
- } |
+ } |
idDesc.fSampleConfig = GrRenderTarget::kUnified_SampleConfig; |
GrSurfaceDesc desc; |
@@ -500,7 +502,7 @@ GrRenderTarget* GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDe |
//////////////////////////////////////////////////////////////////////////////// |
bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height, |
- size_t rowBytes, GrPixelConfig srcConfig, |
+ GrPixelConfig srcConfig, |
DrawPreference* drawPreference, |
WritePixelTempDrawInfo* tempDrawInfo) { |
if (kIndex_8_GrPixelConfig == srcConfig || GrPixelConfigIsCompressed(dstSurface->config())) { |
@@ -560,8 +562,8 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height, |
bool GrGLGpu::onWritePixels(GrSurface* surface, |
int left, int top, int width, int height, |
- GrPixelConfig config, const void* buffer, |
- size_t rowBytes) { |
+ GrPixelConfig config, |
+ const SkTArray<SkMipMapLevel>& texels) { |
GrGLTexture* glTex = static_cast<GrGLTexture*>(surface->asTexture()); |
if (!glTex) { |
return false; |
@@ -573,25 +575,20 @@ bool GrGLGpu::onWritePixels(GrSurface* surface, |
} |
this->setScratchTextureUnit(); |
- GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTex->textureID())); |
+ GL_CALL(BindTexture(glTex->target(), glTex->textureID())); |
bool success = false; |
if (GrPixelConfigIsCompressed(glTex->desc().fConfig)) { |
// We check that config == desc.fConfig in GrGLGpu::canWriteTexturePixels() |
SkASSERT(config == glTex->desc().fConfig); |
- success = this->uploadCompressedTexData(glTex->desc(), buffer, false, left, top, width, |
- height); |
+ success = this->uploadCompressedTexData(glTex->desc(), glTex->target(), texels, false, |
+ left, top, width, height); |
} else { |
- success = this->uploadTexData(glTex->desc(), false, left, top, width, height, config, |
- buffer, rowBytes); |
+ success = this->uploadTexData(glTex->desc(), glTex->target(), false, left, top, width, |
+ height, config, texels); |
} |
- if (success) { |
- glTex->texturePriv().dirtyMipMaps(true); |
- return true; |
- } |
- |
- return false; |
+ return success; |
} |
static inline GrGLenum check_alloc_error(const GrSurfaceDesc& desc, |
@@ -603,36 +600,17 @@ 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 (!GrSurfacePriv::AdjustWritePixelParams(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()) { |
+/** |
+ * 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 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 |
@@ -640,59 +618,92 @@ 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; |
+} |
+/** |
+ * Determines if sized internal formats are available for the texture being created. |
+ * |
+ * @param useTexStorage The result of a call to can_use_tex_storage(). |
+ * @param caps The capabilities of the GL device. |
+ * @param standard The GL standard in use. |
+ * @param version The GL version in use. |
+ * @param dataConfig The pixel configuration for the texture being created. |
+ */ |
+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; |
+} |
- /* |
- * 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; |
- } |
+/** |
+ * Prior to a texture being created, the image may need to be flipped vertically. This function |
+ * prepares the texels for texture creation. |
+ * |
+ * @param desc The surface descriptor for the texture being created. |
+ * @param caps The capabilities of the GL device. |
+ * @param interface The GL interface in use. |
+ * @param swFlipY Should software be used when flipping a texture vertically? |
+ * @param glFlipY Should GL be used when flipping a texture vertically? |
+ * @param width The width of the texture in texels. |
+ * @param height The height of the texture in texels. |
+ * @param bpp The bits per pixel (or texel, really) of the texture. |
+ * @param texels An array of mipmap levels which contain the texel data at that level. |
+ * @param tempStorage In the case where the image needs to be flipped vertically, it will |
+ * use tempStorage as a buffer. |
+ * @param restoreGLRowLength After the texture is created, will the GL row length unpacking need |
+ * to be restored? |
+ */ |
+static void prepare_image_for_writing_to_texture(const GrSurfaceDesc& desc, const GrGLCaps& caps, |
+ const GrGLInterface& interface, bool swFlipY, |
+ bool glFlipY, int bpp, |
+ SkTArray<SkMipMapLevel>& texels, |
+ SkAutoSMalloc<128 * 128>& tempStorage, |
+ bool* restoreGLRowLength) { |
+ for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
+ if (texels[currentMipLevel].fTexels == nullptr) { |
+ continue; |
} |
- if (this->glCaps().unpackRowLengthSupport() && !swFlipY) { |
+ |
+ const size_t trimRowBytes = texels[currentMipLevel].fWidth * 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. |
+ */ |
+ *restoreGLRowLength = false; |
+ |
+ const size_t rowBytes = texels[currentMipLevel].fRowBytes; |
+ 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); |
- GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength)); |
- restoreGLRowLength = true; |
+ GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength)); |
+ *restoreGLRowLength = true; |
} |
} else { |
if (trimRowBytes != rowBytes || swFlipY) { |
+ const uint32_t height = texels[currentMipLevel].fHeight; |
// copy data into our new storage, skipping the trailing bytes |
- size_t trimSize = height * trimRowBytes; |
- const char* src = (const char*)data; |
- if (swFlipY) { |
+ const size_t trimSize = height * trimRowBytes; |
+ const char* src = (const char*)texels[currentMipLevel].fTexels; |
+ if (swFlipY && height >= 1) { |
src += (height - 1) * rowBytes; |
} |
char* dst = (char*)tempStorage.reset(trimSize); |
- for (int y = 0; y < height; y++) { |
+ for (uint32_t y = 0; y < height; y++) { |
memcpy(dst, src, trimRowBytes); |
if (swFlipY) { |
src -= rowBytes; |
@@ -702,70 +713,291 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, |
dst += trimRowBytes; |
} |
// now point data to our copied version |
- data = tempStorage.get(); |
+ texels[currentMipLevel] = SkMipMapLevel(tempStorage.get(), trimRowBytes, |
+ texels[currentMipLevel].fWidth, |
+ texels[currentMipLevel].fHeight); |
} |
} |
if (glFlipY) { |
- GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_TRUE)); |
+ GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_TRUE)); |
} |
- GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, |
- static_cast<GrGLint>(GrUnpackAlignment(dataConfig)))); |
+ GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ALIGNMENT, |
+ static_cast<GrGLint>(GrUnpackAlignment(desc.fConfig)))); |
} |
- 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)); |
+} |
+ |
+/** |
+ * 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 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. |
+ * @param texels The texel data of the texture being created. |
+ * @param succeeded Set to true if allocating and populating the texture completed |
+ * without error. |
+ */ |
+static void allocate_and_populate_uncompressed_texture(const GrSurfaceDesc& desc, |
+ const GrGLInterface& interface, |
+ GrGLenum target, |
+ bool useTexStorage, |
+ GrGLenum internalFormat, |
+ GrGLenum externalFormat, |
+ GrGLenum externalType, |
+ const SkTArray<SkMipMapLevel>& texels, |
+ bool* succeeded) { |
+ CLEAR_ERROR_BEFORE_ALLOC(&interface); |
+ if (useTexStorage) { |
+ // We never resize or change formats of textures. |
+ GL_ALLOC_CALL(&interface, |
+ TexStorage2D(target, |
+ texels.count(), |
+ internalFormat, |
+ desc.fWidth, desc.fHeight)); |
+ |
+ GrGLenum error = check_alloc_error(desc, &interface); |
+ if (error != GR_GL_NO_ERROR) { |
+ *succeeded = false; |
} else { |
- GL_ALLOC_CALL(this->glInterface(), |
- TexImage2D(GR_GL_TEXTURE_2D, |
- 0, // level |
+ for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
+ const void* currentMipData = texels[currentMipLevel].fTexels; |
+ if (currentMipData == nullptr) { |
+ continue; |
+ } |
+ |
+ GR_GL_CALL(&interface, |
+ TexSubImage2D(GR_GL_TEXTURE_2D, |
+ currentMipLevel, |
+ 0, // left |
+ 0, // top |
+ texels[currentMipLevel].fWidth, |
+ texels[currentMipLevel].fHeight, |
+ externalFormat, externalType, |
+ currentMipData)); |
+ } |
+ *succeeded = true; |
+ } |
+ } else { |
+ *succeeded = true; |
+ for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
+ GL_ALLOC_CALL(&interface, |
+ TexImage2D(target, |
+ currentMipLevel, |
internalFormat, |
- desc.fWidth, desc.fHeight, |
+ texels[currentMipLevel].fWidth, |
+ texels[currentMipLevel].fHeight, |
0, // border |
externalFormat, externalType, |
- data)); |
+ texels[currentMipLevel].fTexels)); |
+ GrGLenum error = check_alloc_error(desc, &interface); |
+ if (error != GR_GL_NO_ERROR) { |
+ *succeeded = false; |
+ break; |
+ } |
} |
- GrGLenum error = check_alloc_error(desc, this->glInterface()); |
+ } |
+} |
+ |
+/** |
+ * 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 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. |
+ */ |
+static bool allocate_and_populate_compressed_texture(const GrSurfaceDesc& desc, |
+ const GrGLInterface& interface, |
+ GrGLenum target, |
+ bool useTexStorage, GrGLenum internalFormat, |
+ const SkTArray<SkMipMapLevel>& texels) { |
+ CLEAR_ERROR_BEFORE_ALLOC(&interface); |
+ if (useTexStorage) { |
+ // We never resize or change formats of textures. |
+ GL_ALLOC_CALL(&interface, |
+ TexStorage2D(target, |
+ texels.count(), |
+ internalFormat, |
+ desc.fWidth, desc.fHeight)); |
+ GrGLenum error = check_alloc_error(desc, &interface); |
if (error != GR_GL_NO_ERROR) { |
- succeeded = false; |
+ return false; |
} 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)); |
+ for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
+ const void* currentMipData = texels[currentMipLevel].fTexels; |
+ if (currentMipData == nullptr) { |
+ continue; |
+ } |
+ |
+ const uint32_t width = texels[currentMipLevel].fWidth; |
+ const uint32_t height = texels[currentMipLevel].fHeight; |
+ |
+ // 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); |
+ GR_GL_CALL(&interface, CompressedTexSubImage2D(GR_GL_TEXTURE_2D, |
+ currentMipLevel, |
+ 0, // left |
+ 0, // top |
+ width, height, |
+ internalFormat, SkToInt(dataSize), |
+ currentMipData)); |
} |
} |
} else { |
- if (swFlipY || glFlipY) { |
- top = desc.fHeight - (top + height); |
+ for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
+ const uint32_t width = texels[currentMipLevel].fWidth; |
+ const uint32_t height = texels[currentMipLevel].fHeight; |
+ |
+ // 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); |
+ |
+ GL_ALLOC_CALL(&interface, |
+ CompressedTexImage2D(target, |
+ texels.count(), |
+ internalFormat, |
+ width, height, |
+ 0, // border |
+ SkToInt(dataSize), |
+ texels[currentMipLevel].fTexels)); |
+ |
+ GrGLenum error = check_alloc_error(desc, &interface); |
+ if (error != GR_GL_NO_ERROR) { |
+ return false; |
+ } |
} |
- GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D, |
- 0, // level |
- left, top, |
- width, height, |
- externalFormat, externalType, data)); |
} |
+ return true; |
+} |
+/** |
+ * After a texture is created, any state which was altered during its creation |
+ * needs to be restored. |
+ * |
+ * @param interface The GL interface to use. |
+ * @param caps The capabilities of the GL device. |
+ * @param restoreGLRowLength Should the row length unpacking be restored? |
+ * @param glFlipY Did GL flip the texture vertically? |
+ */ |
+static void restore_pixelstore_state(const GrGLInterface& interface, const GrGLCaps& caps, |
+ bool restoreGLRowLength, bool glFlipY) { |
if (restoreGLRowLength) { |
- SkASSERT(this->glCaps().unpackRowLengthSupport()); |
- GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0)); |
+ SkASSERT(caps.unpackRowLengthSupport()); |
+ GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0)); |
} |
if (glFlipY) { |
- GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_FALSE)); |
+ GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_FALSE)); |
} |
+} |
+ |
+bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, |
+ GrGLenum target, |
+ bool isNewTexture, |
+ int left, int top, int width, int height, |
+ GrPixelConfig dataConfig, |
+ const SkTArray<SkMipMapLevel>& texels) { |
+ // If we're uploading compressed data then we should be using uploadCompressedTexData |
+ SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); |
+ |
+ SkTArray<SkMipMapLevel> texelsCopy(texels); |
+ |
+ for (int currentMipLevel = texelsCopy.count() - 1; currentMipLevel >= 0; currentMipLevel--) { |
+ //SkASSERT(texelsCopy[currentMipLevel].fTexels || isNewTexture); |
+ } |
+ |
+ |
+ const GrGLInterface* interface = this->glInterface(); |
+ const GrGLCaps& caps = this->glCaps(); |
+ GrGLStandard standard = this->glStandard(); |
+ GrGLVersion version = this->glVersion(); |
+ |
+ size_t bpp = GrBytesPerPixel(dataConfig); |
+ for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
+ if (texelsCopy[currentMipLevel].fTexels == nullptr) { |
+ continue; |
+ } |
+ |
+ if (texelsCopy[currentMipLevel].fHeight > SK_MaxS32 |
+ || texelsCopy[currentMipLevel].fWidth > SK_MaxS32) { |
+ return false; |
+ } |
+ int currentMipHeight = texelsCopy[currentMipLevel].fHeight; |
+ int currentMipWidth = texelsCopy[currentMipLevel].fWidth; |
+ if (!GrSurfacePriv::AdjustWritePixelParams(desc.fWidth, desc.fHeight, bpp, &left, &top, |
+ ¤tMipWidth, |
+ ¤tMipHeight, |
+ &texelsCopy[currentMipLevel].fTexels, |
+ &texelsCopy[currentMipLevel].fRowBytes)) { |
+ return false; |
+ } |
+ if (currentMipWidth < 0 || currentMipHeight < 0) { |
+ return false; |
+ } |
+ texelsCopy[currentMipLevel].fWidth = currentMipWidth; |
+ texelsCopy[currentMipLevel].fHeight = currentMipHeight; |
+ } |
+ |
+ bool useTexStorage = can_use_tex_storage(caps, standard, desc); |
+ bool useSizedFormat = can_use_sized_format(useTexStorage, caps, standard, version, 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 (caps.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; |
+ prepare_image_for_writing_to_texture(desc, caps, *interface, swFlipY, glFlipY, bpp, texelsCopy, |
+ tempStorage, &restoreGLRowLength); |
+ bool succeeded = true; |
+ if (isNewTexture && |
+ 0 == left && 0 == top && |
+ desc.fWidth == width && desc.fHeight == height) { |
+ allocate_and_populate_uncompressed_texture(desc, *interface, useTexStorage, internalFormat, |
+ externalFormat, externalType, target, |
+ texelsCopy, &succeeded); |
+ } else { |
+ if (swFlipY || glFlipY) { |
+ top = desc.fHeight - (top + height); |
+ } |
+ for (int currentMipLevel = 0; currentMipLevel < texelsCopy.count(); currentMipLevel++) { |
+ if (texelsCopy[currentMipLevel].fTexels == nullptr) { |
+ continue; |
+ } |
+ |
+ GL_CALL(TexSubImage2D(target, |
+ currentMipLevel, |
+ left, top, |
+ texelsCopy[currentMipLevel].fWidth, |
+ texelsCopy[currentMipLevel].fHeight, |
+ externalFormat, externalType, |
+ texelsCopy[currentMipLevel].fTexels)); |
+ } |
+ } |
+ |
+ restore_pixelstore_state(*interface, caps, restoreGLRowLength, glFlipY); |
+ |
return succeeded; |
} |
@@ -775,14 +1007,19 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, |
// the proper upload semantics. Then users can construct this function how they |
// see fit if they want to go against the "standard" way to do it. |
bool GrGLGpu::uploadCompressedTexData(const GrSurfaceDesc& desc, |
- const void* data, |
+ GrGLenum target, |
+ const SkTArray<SkMipMapLevel>& texels, |
bool isNewTexture, |
int left, int top, int width, int height) { |
- SkASSERT(data || isNewTexture); |
+ SkASSERT(isNewTexture); |
// No support for software flip y, yet... |
SkASSERT(kBottomLeft_GrSurfaceOrigin != desc.fOrigin); |
+ const GrGLInterface* interface = this->glInterface(); |
+ const GrGLCaps& caps = this->glCaps(); |
+ GrGLStandard standard = this->glStandard(); |
+ |
if (-1 == width) { |
width = desc.fWidth; |
} |
@@ -801,9 +1038,7 @@ bool GrGLGpu::uploadCompressedTexData(const GrSurfaceDesc& desc, |
} |
#endif |
- // 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); |
+ bool useTexStorage = can_use_tex_storage(caps, standard, desc); |
// We only need the internal format for compressed 2D textures. |
GrGLenum internalFormat = 0; |
@@ -812,31 +1047,32 @@ 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; |
- } |
+ return allocate_and_populate_compressed_texture(desc, *interface, target, useTexStorage, |
+ internalFormat, texels); |
} else { |
// Paletted textures can't be updated. |
if (GR_GL_PALETTE8_RGBA8 == internalFormat) { |
return false; |
} |
- GL_CALL(CompressedTexSubImage2D(GR_GL_TEXTURE_2D, |
- 0, // level |
- left, top, |
- width, height, |
- internalFormat, |
- SkToInt(dataSize), |
- data)); |
+ for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { |
+ if (texels[currentMipLevel].fTexels == nullptr) { |
+ continue; |
+ } |
+ |
+ // 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, |
+ texels[currentMipLevel].fWidth, |
+ texels[currentMipLevel].fHeight); |
+ GL_CALL(CompressedTexSubImage2D(target, |
+ currentMipLevel, |
+ left, top, |
+ texels[currentMipLevel].fWidth, |
+ texels[currentMipLevel].fHeight, |
+ internalFormat, |
+ dataSize, |
+ texels[currentMipLevel].fTexels)); |
+ } |
} |
return true; |
@@ -884,6 +1120,7 @@ static bool renderbuffer_storage_msaa(const GrGLContext& ctx, |
bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, |
GrGpuResource::LifeCycle lifeCycle, |
GrGLuint texID, |
+ GrGLenum textureTarget, |
GrGLRenderTarget::IDDesc* idDesc) { |
idDesc->fMSColorRenderbufferID = 0; |
idDesc->fRTFBOID = 0; |
@@ -942,9 +1179,9 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, |
fStats.incRenderTargetBinds(); |
GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, idDesc->fRTFBOID)); |
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, |
- GR_GL_COLOR_ATTACHMENT0, |
- GR_GL_RENDERBUFFER, |
- idDesc->fMSColorRenderbufferID)); |
+ GR_GL_COLOR_ATTACHMENT0, |
+ GR_GL_RENDERBUFFER, |
+ idDesc->fMSColorRenderbufferID)); |
if ((desc.fFlags & kCheckAllocation_GrSurfaceFlag) || |
!this->glCaps().isConfigVerifiedColorAttachment(desc.fConfig)) { |
GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); |
@@ -960,12 +1197,12 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, |
if (this->glCaps().usesImplicitMSAAResolve() && desc.fSampleCnt > 0) { |
GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER, |
GR_GL_COLOR_ATTACHMENT0, |
- GR_GL_TEXTURE_2D, |
+ textureTarget, |
texID, 0, desc.fSampleCnt)); |
} else { |
GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, |
GR_GL_COLOR_ATTACHMENT0, |
- GR_GL_TEXTURE_2D, |
+ textureTarget, |
texID, 0)); |
} |
if ((desc.fFlags & kCheckAllocation_GrSurfaceFlag) || |
@@ -1004,9 +1241,46 @@ 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; |
+ // We only support GL_TEXTURE_2D at the moment. |
+ idDesc.fTarget = GR_GL_TEXTURE_2D; |
+ return idDesc; |
+} |
+ |
+static GrGLTexture::TexParams set_initial_texture_params(const GrGLInterface* interface, |
+ GrGLTexture::IDDesc idDesc) { |
+ // 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(idDesc.fTarget, |
+ GR_GL_TEXTURE_MAG_FILTER, |
+ initialTexParams.fMagFilter)); |
+ GR_GL_CALL(interface, TexParameteri(idDesc.fTarget, |
+ GR_GL_TEXTURE_MIN_FILTER, |
+ initialTexParams.fMinFilter)); |
+ GR_GL_CALL(interface, TexParameteri(idDesc.fTarget, |
+ GR_GL_TEXTURE_WRAP_S, |
+ initialTexParams.fWrapS)); |
+ GR_GL_CALL(interface, TexParameteri(idDesc.fTarget, |
+ GR_GL_TEXTURE_WRAP_T, |
+ initialTexParams.fWrapT)); |
+ return initialTexParams; |
+} |
+ |
GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, |
GrGpuResource::LifeCycle lifeCycle, |
- const void* srcData, size_t rowBytes) { |
+ const SkTArray<SkMipMapLevel>& texels) { |
// 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."); |
@@ -1015,49 +1289,27 @@ 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; |
- |
+ GrGLTexture::IDDesc 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)); |
+ GL_CALL(BindTexture(idDesc.fTarget, idDesc.fTextureID)); |
if (renderTarget && this->glCaps().textureUsageSupport()) { |
// provides a hint about how this texture will be used |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
+ GL_CALL(TexParameteri(idDesc.fTarget, |
GR_GL_TEXTURE_USAGE, |
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)); |
- if (!this->uploadTexData(desc, true, 0, 0, |
+ GrGLTexture::TexParams initialTexParams = set_initial_texture_params(this->glInterface(), |
+ idDesc); |
+ |
+ if (!this->uploadTexData(desc, GR_GL_TEXTURE_2D, true, 0, 0, |
desc.fWidth, desc.fHeight, |
- desc.fConfig, srcData, rowBytes)) { |
+ desc.fConfig, texels)) { |
GL_CALL(DeleteTextures(1, &idDesc.fTextureID)); |
return return_null_texture(); |
} |
@@ -1065,10 +1317,11 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, |
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)); |
+ GL_CALL(BindTexture(idDesc.fTarget, 0)); |
GrGLRenderTarget::IDDesc rtIDDesc; |
- if (!this->createRenderTargetObjects(desc, lifeCycle, idDesc.fTextureID, &rtIDDesc)) { |
+ if (!this->createRenderTargetObjects(desc, lifeCycle, idDesc.fTextureID, idDesc.fTarget, |
+ &rtIDDesc)) { |
GL_CALL(DeleteTextures(1, &idDesc.fTextureID)); |
return return_null_texture(); |
} |
@@ -1086,47 +1339,24 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, |
GrTexture* GrGLGpu::onCreateCompressedTexture(const GrSurfaceDesc& desc, |
GrGpuResource::LifeCycle lifeCycle, |
- const void* srcData) { |
+ const SkTArray<SkMipMapLevel>& texels) { |
// Make sure that we're not flipping Y. |
if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { |
return return_null_texture(); |
} |
- GrGLTexture::IDDesc idDesc; |
- GL_CALL(GenTextures(1, &idDesc.fTextureID)); |
- idDesc.fLifeCycle = lifeCycle; |
- |
+ GrGLTexture::IDDesc 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)); |
+ GL_CALL(BindTexture(idDesc.fTarget, 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)); |
- |
- if (!this->uploadCompressedTexData(desc, srcData)) { |
+ GrGLTexture::TexParams initialTexParams = set_initial_texture_params(this->glInterface(), |
+ idDesc); |
+ |
+ if (!this->uploadCompressedTexData(desc, GR_GL_TEXTURE_2D, texels)) { |
GL_CALL(DeleteTextures(1, &idDesc.fTextureID)); |
return return_null_texture(); |
} |
@@ -1476,7 +1706,7 @@ bool GrGLGpu::flushGLState(const DrawArgs& args) { |
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget()); |
this->flushStencil(pipeline.getStencil()); |
this->flushScissor(pipeline.getScissorState(), glRT->getViewport(), glRT->origin()); |
- this->flushHWAAState(glRT, pipeline.isHWAntialiasState()); |
+ this->flushHWAAState(glRT, pipeline.isHWAntialiasState(), !pipeline.getStencil().isDisabled()); |
// This must come after textures are flushed because a texture may need |
// to be msaa-resolved (which will modify bound FBO state). |
@@ -1899,6 +2129,22 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, |
return true; |
} |
+void GrGLGpu::setColocatedSampleLocations(GrRenderTarget* rt, bool useColocatedSampleLocations) { |
+ GrGLRenderTarget* target = static_cast<GrGLRenderTarget*>(rt->asRenderTarget()); |
+ SkASSERT(0 != target->renderFBOID()); |
+ |
+ if (!rt->isStencilBufferMultisampled() || |
+ useColocatedSampleLocations == target->usesColocatedSampleLocations()) { |
+ return; |
+ } |
+ |
+ GL_CALL(NamedFramebufferParameteri(target->renderFBOID(), |
+ GR_GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS, |
+ useColocatedSampleLocations)); |
+ |
+ target->flagAsUsingColocatedSampleLocations(useColocatedSampleLocations); |
+} |
+ |
void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) { |
SkASSERT(target); |
@@ -2146,9 +2392,19 @@ void GrGLGpu::flushStencil(const GrStencilSettings& stencilSettings) { |
} |
} |
-void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA) { |
+void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabled) { |
SkASSERT(!useHWAA || rt->isStencilBufferMultisampled()); |
+ if (rt->hasMixedSamples() && stencilEnabled && |
+ this->glCaps().glslCaps()->programmableSampleLocationsSupport()) { |
+ if (useHWAA) { |
+ this->setColocatedSampleLocations(rt, false); |
+ } else { |
+ this->setColocatedSampleLocations(rt, true); |
+ } |
+ useHWAA = true; |
+ } |
+ |
if (this->glCaps().multisampleDisableSupport()) { |
if (useHWAA) { |
if (kYes_TriState != fMSAAEnabled) { |
@@ -2246,6 +2502,18 @@ static inline GrGLenum tile_to_gl_wrap(SkShader::TileMode tm) { |
void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture) { |
SkASSERT(texture); |
+#ifdef SK_DEBUG |
+ if (!this->caps()->npotTextureTileSupport()) { |
+ const bool tileX = SkShader::kClamp_TileMode != params.getTileModeX(); |
+ const bool tileY = SkShader::kClamp_TileMode != params.getTileModeY(); |
+ if (tileX || tileY) { |
+ const int w = texture->width(); |
+ const int h = texture->height(); |
+ SkASSERT(SkIsPow2(w) && SkIsPow2(h)); |
+ } |
+ } |
+#endif |
+ |
// If we created a rt/tex and rendered to it without using a texture and now we're texturing |
// from the rt it will still be the last bound texture, but it needs resolving. So keep this |
// out of the "last != next" check. |
@@ -2255,9 +2523,10 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTextur |
} |
uint32_t textureID = texture->getUniqueID(); |
+ GrGLenum target = texture->target(); |
if (fHWBoundTextureUniqueIDs[unitIdx] != textureID) { |
this->setTextureUnit(unitIdx); |
- GL_CALL(BindTexture(GR_GL_TEXTURE_2D, texture->textureID())); |
+ GL_CALL(BindTexture(target, texture->textureID())); |
fHWBoundTextureUniqueIDs[unitIdx] = textureID; |
} |
@@ -2289,7 +2558,7 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTextur |
if (GrTextureParams::kMipMap_FilterMode == filterMode && |
texture->texturePriv().mipMapsAreDirty()) { |
- GL_CALL(GenerateMipmap(GR_GL_TEXTURE_2D)); |
+ GL_CALL(GenerateMipmap(target)); |
texture->texturePriv().dirtyMipMaps(false); |
} |
@@ -2300,27 +2569,19 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTextur |
sizeof(newTexParams.fSwizzleRGBA)); |
if (setAll || newTexParams.fMagFilter != oldTexParams.fMagFilter) { |
this->setTextureUnit(unitIdx); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_MAG_FILTER, |
- newTexParams.fMagFilter)); |
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAG_FILTER, newTexParams.fMagFilter)); |
} |
if (setAll || newTexParams.fMinFilter != oldTexParams.fMinFilter) { |
this->setTextureUnit(unitIdx); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_MIN_FILTER, |
- newTexParams.fMinFilter)); |
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER, newTexParams.fMinFilter)); |
} |
if (setAll || newTexParams.fWrapS != oldTexParams.fWrapS) { |
this->setTextureUnit(unitIdx); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_WRAP_S, |
- newTexParams.fWrapS)); |
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_S, newTexParams.fWrapS)); |
} |
if (setAll || newTexParams.fWrapT != oldTexParams.fWrapT) { |
this->setTextureUnit(unitIdx); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
- GR_GL_TEXTURE_WRAP_T, |
- newTexParams.fWrapT)); |
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_T, newTexParams.fWrapT)); |
} |
if (this->glCaps().textureSwizzleSupport() && |
(setAll || memcmp(newTexParams.fSwizzleRGBA, |
@@ -2330,14 +2591,14 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTextur |
if (this->glStandard() == kGLES_GrGLStandard) { |
// ES3 added swizzle support but not GL_TEXTURE_SWIZZLE_RGBA. |
const GrGLenum* swizzle = newTexParams.fSwizzleRGBA; |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_R, swizzle[0])); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_G, swizzle[1])); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_B, swizzle[2])); |
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_A, swizzle[3])); |
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_R, swizzle[0])); |
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_G, swizzle[1])); |
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_B, swizzle[2])); |
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_A, swizzle[3])); |
} else { |
GR_STATIC_ASSERT(sizeof(newTexParams.fSwizzleRGBA[0]) == sizeof(GrGLint)); |
const GrGLint* swizzle = reinterpret_cast<const GrGLint*>(newTexParams.fSwizzleRGBA); |
- GL_CALL(TexParameteriv(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_RGBA, swizzle)); |
+ GL_CALL(TexParameteriv(target, GR_GL_TEXTURE_SWIZZLE_RGBA, swizzle)); |
} |
} |
texture->setCachedTexParams(newTexParams, this->getResetTimestamp()); |
@@ -2550,7 +2811,7 @@ bool GrGLGpu::configToGLFormats(GrPixelConfig config, |
*externalType = GR_GL_HALF_FLOAT_OES; |
} |
break; |
- |
+ |
case kRGBA_half_GrPixelConfig: |
*internalFormat = GR_GL_RGBA16F; |
*externalFormat = GR_GL_RGBA; |
@@ -2643,12 +2904,13 @@ inline bool can_copy_texsubimage(const GrSurface* dst, |
// If a temporary FBO was created, its non-zero ID is returned. The viewport that the copy rect is |
// relative to is output. |
-GrGLuint GrGLGpu::bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, |
- TempFBOTarget tempFBOTarget) { |
+void GrGLGpu::bindSurfaceFBOForCopy(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, |
+ TempFBOTarget tempFBOTarget) { |
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget()); |
if (nullptr == rt) { |
SkASSERT(surface->asTexture()); |
GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID(); |
+ GrGLenum target = static_cast<GrGLTexture*>(surface->asTexture())->target(); |
GrGLuint* tempFBOID; |
tempFBOID = kSrc_TempFBOTarget == tempFBOTarget ? &fTempSrcFBOID : &fTempDstFBOID; |
@@ -2660,29 +2922,31 @@ GrGLuint GrGLGpu::bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLI |
GR_GL_CALL(this->glInterface(), BindFramebuffer(fboTarget, *tempFBOID)); |
GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, |
GR_GL_COLOR_ATTACHMENT0, |
- GR_GL_TEXTURE_2D, |
+ target, |
texID, |
0)); |
viewport->fLeft = 0; |
viewport->fBottom = 0; |
viewport->fWidth = surface->width(); |
viewport->fHeight = surface->height(); |
- return *tempFBOID; |
} else { |
- GrGLuint tempFBOID = 0; |
fStats.incRenderTargetBinds(); |
GR_GL_CALL(this->glInterface(), BindFramebuffer(fboTarget, rt->renderFBOID())); |
*viewport = rt->getViewport(); |
- return tempFBOID; |
} |
} |
-void GrGLGpu::unbindTextureFromFBO(GrGLenum fboTarget) { |
- GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, |
- GR_GL_COLOR_ATTACHMENT0, |
- GR_GL_TEXTURE_2D, |
- 0, |
- 0)); |
+void GrGLGpu::unbindTextureFBOForCopy(GrGLenum fboTarget, GrSurface* surface) { |
+ // bindSurfaceFBOForCopy temporarily binds textures that are not render targets to |
+ if (!surface->asRenderTarget()) { |
+ SkASSERT(surface->asTexture()); |
+ GrGLenum textureTarget = static_cast<GrGLTexture*>(surface->asTexture())->target(); |
+ GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, |
+ GR_GL_COLOR_ATTACHMENT0, |
+ textureTarget, |
+ 0, |
+ 0)); |
+ } |
} |
bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const { |
@@ -2745,7 +3009,7 @@ bool GrGLGpu::onCopySurface(GrSurface* dst, |
this->copySurfaceAsDraw(dst, src, srcRect, dstPoint); |
return true; |
} |
- |
+ |
if (can_copy_texsubimage(dst, src, this)) { |
this->copySurfaceAsCopyTexSubImage(dst, src, srcRect, dstPoint); |
return true; |
@@ -2769,7 +3033,7 @@ void GrGLGpu::createCopyProgram() { |
GrGLShaderVar uTexture("u_texture", kSampler2D_GrSLType, GrShaderVar::kUniform_TypeModifier); |
GrGLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier); |
GrGLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier); |
- |
+ |
SkString vshaderTxt(version); |
aVertex.appendDecl(this->ctxInfo(), &vshaderTxt); |
vshaderTxt.append(";"); |
@@ -2779,7 +3043,7 @@ void GrGLGpu::createCopyProgram() { |
vshaderTxt.append(";"); |
vTexCoord.appendDecl(this->ctxInfo(), &vshaderTxt); |
vshaderTxt.append(";"); |
- |
+ |
vshaderTxt.append( |
"// Copy Program VS\n" |
"void main() {" |
@@ -2813,7 +3077,7 @@ void GrGLGpu::createCopyProgram() { |
fsOutName, |
GrGLSLTexture2DFunctionName(kVec2f_GrSLType, this->glslGeneration()) |
); |
- |
+ |
GL_CALL_RET(fCopyProgram.fProgram, CreateProgram()); |
const char* str; |
GrGLint length; |
@@ -2916,7 +3180,7 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst, |
this->flushBlend(blendInfo); |
this->flushColorWrite(true); |
this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace); |
- this->flushHWAAState(dstRT, false); |
+ this->flushHWAAState(dstRT, false, false); |
this->disableScissor(); |
GrStencilSettings stencil; |
stencil.setDisabled(); |
@@ -2930,9 +3194,8 @@ void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, |
const SkIRect& srcRect, |
const SkIPoint& dstPoint) { |
SkASSERT(can_copy_texsubimage(dst, src, this)); |
- GrGLuint srcFBO; |
GrGLIRect srcVP; |
- srcFBO = this->bindSurfaceAsFBO(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget); |
+ this->bindSurfaceFBOForCopy(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget); |
GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture()); |
SkASSERT(dstTex); |
// We modified the bound FBO |
@@ -2946,20 +3209,18 @@ void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, |
src->origin()); |
this->setScratchTextureUnit(); |
- GL_CALL(BindTexture(GR_GL_TEXTURE_2D, dstTex->textureID())); |
+ GL_CALL(BindTexture(dstTex->target(), dstTex->textureID())); |
GrGLint dstY; |
if (kBottomLeft_GrSurfaceOrigin == dst->origin()) { |
dstY = dst->height() - (dstPoint.fY + srcGLRect.fHeight); |
} else { |
dstY = dstPoint.fY; |
} |
- GL_CALL(CopyTexSubImage2D(GR_GL_TEXTURE_2D, 0, |
+ GL_CALL(CopyTexSubImage2D(dstTex->target(), 0, |
dstPoint.fX, dstY, |
srcGLRect.fLeft, srcGLRect.fBottom, |
srcGLRect.fWidth, srcGLRect.fHeight)); |
- if (srcFBO) { |
- this->unbindTextureFromFBO(GR_GL_FRAMEBUFFER); |
- } |
+ this->unbindTextureFBOForCopy(GR_GL_FRAMEBUFFER, src); |
} |
bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, |
@@ -2975,14 +3236,10 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, |
} |
} |
- GrGLuint dstFBO; |
- GrGLuint srcFBO; |
GrGLIRect dstVP; |
GrGLIRect srcVP; |
- dstFBO = this->bindSurfaceAsFBO(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP, |
- kDst_TempFBOTarget); |
- srcFBO = this->bindSurfaceAsFBO(src, GR_GL_READ_FRAMEBUFFER, &srcVP, |
- kSrc_TempFBOTarget); |
+ this->bindSurfaceFBOForCopy(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget); |
+ this->bindSurfaceFBOForCopy(src, GR_GL_READ_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget); |
// We modified the bound FBO |
fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; |
GrGLIRect srcGLRect; |
@@ -3022,12 +3279,8 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, |
dstGLRect.fLeft + dstGLRect.fWidth, |
dstGLRect.fBottom + dstGLRect.fHeight, |
GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); |
- if (dstFBO) { |
- this->unbindTextureFromFBO(GR_GL_DRAW_FRAMEBUFFER); |
- } |
- if (srcFBO) { |
- this->unbindTextureFromFBO(GR_GL_READ_FRAMEBUFFER); |
- } |
+ this->unbindTextureFBOForCopy(GR_GL_DRAW_FRAMEBUFFER, dst); |
+ this->unbindTextureFBOForCopy(GR_GL_READ_FRAMEBUFFER, src); |
return true; |
} |