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