| 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;
|
| }
|
|
|
|
|