diff options
author | Brian Salomon <bsalomon@google.com> | 2018-06-20 16:25:26 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-06-20 21:13:27 +0000 |
commit | 930f939c48af1be6005af12bb6f709ca5da9d118 (patch) | |
tree | 21dbb8b105aa1190237c148358b7993565158335 | |
parent | 2a284de7a51c198096a6f34ec1cbfe9118db554c (diff) |
Ensure that textures exported via SkImage::MakeBackendTextureFromSkImage
have consistent content in their mip map levels.
Bug= chromium:850617
Change-Id: I3ad918aa453bd8e4e625eb145de6ba2a5dab7b0c
Reviewed-on: https://skia-review.googlesource.com/136230
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
-rw-r--r-- | src/gpu/GrDrawingManager.cpp | 14 | ||||
-rw-r--r-- | src/gpu/GrGpu.cpp | 13 | ||||
-rw-r--r-- | src/gpu/GrGpu.h | 8 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 88 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 9 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 22 | ||||
-rw-r--r-- | src/gpu/mock/GrMockGpu.h | 2 | ||||
-rw-r--r-- | src/gpu/mtl/GrMtlGpu.h | 2 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.cpp | 54 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.h | 4 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpuCommandBuffer.cpp | 3 | ||||
-rw-r--r-- | tests/GrTextureMipMapInvalidationTest.cpp | 54 |
12 files changed, 151 insertions, 122 deletions
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp index 7c6338f3d2..2b8c26213d 100644 --- a/src/gpu/GrDrawingManager.cpp +++ b/src/gpu/GrDrawingManager.cpp @@ -19,14 +19,16 @@ #include "GrResourceProvider.h" #include "GrSoftwarePathRenderer.h" #include "GrSurfaceProxyPriv.h" +#include "GrTexture.h" #include "GrTextureContext.h" #include "GrTextureOpList.h" +#include "GrTexturePriv.h" #include "GrTextureProxy.h" #include "GrTextureProxyPriv.h" +#include "GrTracing.h" #include "SkDeferredDisplayList.h" #include "SkSurface_Gpu.h" #include "SkTTopoSort.h" -#include "GrTracing.h" #include "ccpr/GrCoverageCountingPathRenderer.h" #include "text/GrTextContext.h" @@ -377,8 +379,14 @@ GrSemaphoresSubmitted GrDrawingManager::prepareSurfaceForExternalIO( } GrSurface* surface = proxy->priv().peekSurface(); - if (surface->asRenderTarget()) { - gpu->resolveRenderTarget(surface->asRenderTarget()); + if (auto* rt = surface->asRenderTarget()) { + gpu->resolveRenderTarget(rt); + } + if (auto* tex = surface->asTexture()) { + if (tex->texturePriv().mipMapped() == GrMipMapped::kYes && + tex->texturePriv().mipMapsAreDirty()) { + gpu->regenerateMipMapLevels(tex); + } } return result; } diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index 3ebfa364d4..4b7e786f87 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -291,6 +291,19 @@ bool GrGpu::transferPixels(GrTexture* texture, int left, int top, int width, int return false; } +bool GrGpu::regenerateMipMapLevels(GrTexture* texture) { + SkASSERT(texture); + SkASSERT(this->caps()->mipMapSupport()); + SkASSERT(texture->texturePriv().mipMapped() == GrMipMapped::kYes); + SkASSERT(texture->texturePriv().mipMapsAreDirty()); + SkASSERT(!texture->asRenderTarget() || !texture->asRenderTarget()->needsResolve()); + if (this->onRegenerateMipMapLevels(texture)) { + texture->texturePriv().markMipMapsClean(); + return true; + } + return false; +} + void GrGpu::resolveRenderTarget(GrRenderTarget* target) { SkASSERT(target); this->handleDirtyContext(); diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index d97a22edd0..7ab7995fd7 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -142,6 +142,11 @@ public: void resolveRenderTarget(GrRenderTarget*); /** + * Uses the base of the texture to recompute the contents of the other levels. + */ + bool regenerateMipMapLevels(GrTexture*); + + /** * Reads a rectangle of pixels from a render target. No sRGB/linear conversions are performed. * * @param surface The surface to read from @@ -451,6 +456,9 @@ private: // overridden by backend-specific derived class to perform the resolve virtual void onResolveRenderTarget(GrRenderTarget* target) = 0; + // overridden by backend specific derived class to perform mip map level regeneration. + virtual bool onRegenerateMipMapLevels(GrTexture*) = 0; + // overridden by backend specific derived class to perform the copy surface virtual bool onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src, GrSurfaceOrigin srcOrigin, diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 08bd168368..9e73259a55 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -2716,8 +2716,7 @@ static GrGLenum filter_to_gl_min_filter(GrSamplerState::Filter filter) { return 0; } -void GrGLGpu::bindTexture(int unitIdx, const GrSamplerState& samplerState, GrGLTexture* texture, - GrSurfaceOrigin textureOrigin) { +void GrGLGpu::bindTexture(int unitIdx, const GrSamplerState& samplerState, GrGLTexture* texture) { SkASSERT(texture); #ifdef SK_DEBUG @@ -2858,53 +2857,6 @@ void GrGLGpu::bindTexelBuffer(int unitIdx, GrPixelConfig texelConfig, GrGLBuffer } } -void GrGLGpu::generateMipmaps(const GrSamplerState& params, GrGLTexture* texture, - GrSurfaceOrigin textureOrigin) { - SkASSERT(texture); - - // First, figure out if we need mips for this texture at all: - GrSamplerState::Filter filterMode = params.filter(); - - if (GrSamplerState::Filter::kMipMap == filterMode) { - if (!this->caps()->mipMapSupport() || - texture->texturePriv().mipMapped() == GrMipMapped::kNo) { - filterMode = GrSamplerState::Filter::kBilerp; - } - } - - if (GrSamplerState::Filter::kMipMap != filterMode) { - return; - } - - SkASSERT(texture->texturePriv().mipMapped() == GrMipMapped::kYes); - - // If the mips aren't dirty, we're done: - if (!texture->texturePriv().mipMapsAreDirty()) { - return; - } - - // 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. - GrGLRenderTarget* texRT = static_cast<GrGLRenderTarget*>(texture->asRenderTarget()); - if (texRT) { - this->onResolveRenderTarget(texRT); - } - - GrGLenum target = texture->target(); - this->setScratchTextureUnit(); - GL_CALL(BindTexture(target, texture->textureID())); - - // Either do manual mipmap generation or (if that fails), just rely on the driver: - if (!this->generateMipmap(texture, textureOrigin)) { - GL_CALL(GenerateMipmap(target)); - } - - texture->texturePriv().markMipMapsClean(); - - // We have potentially set lots of state on the texture. Easiest to dirty it all: - texture->textureParamsModified(); -} - void GrGLGpu::setTextureSwizzle(int unitIdx, GrGLenum target, const GrGLenum swizzle[]) { this->setTextureUnit(unitIdx); if (this->glStandard() == kGLES_GrGLStandard) { @@ -3664,7 +3616,7 @@ bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrSurfaceOrigin dstOrigin, int w = srcRect.width(); int h = srcRect.height(); - this->bindTexture(0, GrSamplerState::ClampNearest(), srcTex, srcOrigin); + this->bindTexture(0, GrSamplerState::ClampNearest(), srcTex); GrGLIRect dstVP; this->bindSurfaceFBOForPixelOps(dst, GR_GL_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget); @@ -3820,23 +3772,25 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, GrSurfaceOrigin dstOr return true; } -// Manual implementation of mipmap generation, to work around driver bugs w/sRGB. -// Uses draw calls to do a series of downsample operations to successive mips. -// If this returns false, then the calling code falls back to using glGenerateMipmap. -bool GrGLGpu::generateMipmap(GrGLTexture* texture, GrSurfaceOrigin textureOrigin) { - // Our iterative downsample requires the ability to limit which level we're sampling: - if (!this->glCaps().doManualMipmapping()) { - return false; - } - +bool GrGLGpu::onRegenerateMipMapLevels(GrTexture* texture) { + auto glTex = static_cast<GrGLTexture*>(texture); // Mipmaps are only supported on 2D textures: - if (GR_GL_TEXTURE_2D != texture->target()) { + if (GR_GL_TEXTURE_2D != glTex->target()) { return false; } - // We need to be able to render to the texture for this to work: - if (!this->glCaps().canConfigBeFBOColorAttachment(texture->config())) { - return false; + // Manual implementation of mipmap generation, to work around driver bugs w/sRGB. + // Uses draw calls to do a series of downsample operations to successive mips. + + // The manual approach requires the ability to limit which level we're sampling and that the + // destination can be bound to a FBO: + if (!this->glCaps().doManualMipmapping() || + !this->glCaps().canConfigBeFBOColorAttachment(texture->config())) { + GrGLenum target = glTex->target(); + this->setScratchTextureUnit(); + GL_CALL(BindTexture(target, glTex->textureID())); + GL_CALL(GenerateMipmap(glTex->target())); + return true; } int width = texture->width(); @@ -3854,7 +3808,7 @@ bool GrGLGpu::generateMipmap(GrGLTexture* texture, GrSurfaceOrigin textureOrigin // Bind the texture, to get things configured for filtering. // We'll be changing our base level further below: this->setTextureUnit(0); - this->bindTexture(0, GrSamplerState::ClampBilerp(), texture, textureOrigin); + this->bindTexture(0, GrSamplerState::ClampBilerp(), glTex); // Vertex data: if (!fMipmapProgramArrayBuffer) { @@ -3916,8 +3870,8 @@ bool GrGLGpu::generateMipmap(GrGLTexture* texture, GrSurfaceOrigin textureOrigin // Only sample from previous mip GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_BASE_LEVEL, level - 1)); - GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, - GR_GL_TEXTURE_2D, texture->textureID(), level)); + GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D, + glTex->textureID(), level)); width = SkTMax(1, width / 2); height = SkTMax(1, height / 2); @@ -3932,6 +3886,8 @@ bool GrGLGpu::generateMipmap(GrGLTexture* texture, GrSurfaceOrigin textureOrigin GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D, 0, 0)); + // We modified the base level param. + texture->textureParamsModified(); return true; } diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index 48cd21b426..d08974498a 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -54,14 +54,10 @@ public: } // Used by GrGLProgram to configure OpenGL state. - void bindTexture(int unitIdx, const GrSamplerState& samplerState, GrGLTexture* texture, - GrSurfaceOrigin textureOrigin); + void bindTexture(int unitIdx, const GrSamplerState& samplerState, GrGLTexture* texture); void bindTexelBuffer(int unitIdx, GrPixelConfig, GrGLBuffer*); - void generateMipmaps(const GrSamplerState& params, GrGLTexture* texture, - GrSurfaceOrigin textureOrigin); - // These functions should be used to bind GL objects. They track the GL state and skip redundant // bindings. Making the equivalent glBind calls directly will confuse the state tracking. void bindVertexArray(GrGLuint id) { @@ -244,6 +240,8 @@ private: void onResolveRenderTarget(GrRenderTarget* target) override; + bool onRegenerateMipMapLevels(GrTexture*) override; + bool onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, const SkIPoint& dstPoint, @@ -286,7 +284,6 @@ private: bool copySurfaceAsBlitFramebuffer(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, const SkIPoint& dstPoint); - bool generateMipmap(GrGLTexture* texture, GrSurfaceOrigin textureOrigin); void clearStencilClipAsDraw(const GrFixedClip&, bool insideStencilMask, GrRenderTarget*, GrSurfaceOrigin); diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index 3d4bd380fa..2a876d0851 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -6,15 +6,15 @@ */ #include "GrGLProgram.h" - #include "GrAllocator.h" -#include "GrProcessor.h" #include "GrCoordTransform.h" -#include "GrGLGpu.h" #include "GrGLBuffer.h" +#include "GrGLGpu.h" #include "GrGLPathRendering.h" #include "GrPathProcessor.h" #include "GrPipeline.h" +#include "GrProcessor.h" +#include "GrTexturePriv.h" #include "GrXferProcessor.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLGeometryProcessor.h" @@ -99,8 +99,7 @@ void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline fXferProcessor->setData(fProgramDataManager, xp, dstTexture, offset); if (dstTexture) { fGpu->bindTexture(nextTexSamplerIdx++, GrSamplerState::ClampNearest(), - static_cast<GrGLTexture*>(dstTexture), - pipeline.dstTextureProxy()->origin()); + static_cast<GrGLTexture*>(dstTexture)); } SkASSERT(nextTexSamplerIdx == fNumTextureSamplers); SkASSERT(nextTexelBufferIdx == fNumTextureSamplers + fNumTexelBuffers); @@ -170,8 +169,7 @@ void GrGLProgram::bindTextures(const GrResourceIOProcessor& processor, for (int i = 0; i < processor.numTextureSamplers(); ++i) { const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(i); fGpu->bindTexture((*nextTexSamplerIdx)++, sampler.samplerState(), - static_cast<GrGLTexture*>(sampler.peekTexture()), - sampler.proxy()->origin()); + static_cast<GrGLTexture*>(sampler.peekTexture())); } for (int i = 0; i < processor.numBuffers(); ++i) { const GrResourceIOProcessor::BufferAccess& access = processor.bufferAccess(i); @@ -183,8 +181,12 @@ void GrGLProgram::bindTextures(const GrResourceIOProcessor& processor, void GrGLProgram::generateMipmaps(const GrResourceIOProcessor& processor) { for (int i = 0; i < processor.numTextureSamplers(); ++i) { const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(i); - fGpu->generateMipmaps(sampler.samplerState(), - static_cast<GrGLTexture*>(sampler.peekTexture()), - sampler.proxy()->origin()); + auto* tex = sampler.peekTexture(); + if (sampler.samplerState().filter() == GrSamplerState::Filter::kMipMap && + tex->texturePriv().mipMapped() == GrMipMapped::kYes && + tex->texturePriv().mipMapsAreDirty()) { + SkASSERT(fGpu->caps()->mipMapSupport()); + fGpu->regenerateMipMapLevels(static_cast<GrGLTexture*>(sampler.peekTexture())); + } } } diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h index 3bb4a85772..a8ec3aa36d 100644 --- a/src/gpu/mock/GrMockGpu.h +++ b/src/gpu/mock/GrMockGpu.h @@ -92,6 +92,8 @@ private: return true; } + bool onRegenerateMipMapLevels(GrTexture*) override { return true; } + void onResolveRenderTarget(GrRenderTarget* target) override { return; } void onFinishFlush(bool insertedSemaphores) override {} diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h index e325ad61b0..b230ef73d7 100644 --- a/src/gpu/mtl/GrMtlGpu.h +++ b/src/gpu/mtl/GrMtlGpu.h @@ -113,6 +113,8 @@ private: return false; } + bool onRegenerateMipMapLevels(GrTexture*) override { return false; } + void onResolveRenderTarget(GrRenderTarget* target) override { return; } void onFinishFlush(bool insertedSemaphores) override {} diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index 1149855b1b..1d89566d9c 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -894,11 +894,12 @@ sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendTextureAsRenderTarget(const GrBacken return GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, imageInfo, std::move(layout)); } -void GrVkGpu::generateMipmap(GrVkTexture* tex, GrSurfaceOrigin texOrigin) { +bool GrVkGpu::onRegenerateMipMapLevels(GrTexture* tex) { + auto* vkTex = static_cast<GrVkTexture*>(tex); // don't do anything for linearly tiled textures (can't have mipmaps) - if (tex->isLinearTiled()) { + if (vkTex->isLinearTiled()) { SkDebugf("Trying to create mipmap for linear tiled texture"); - return; + return false; } // determine if we can blit to and from this format @@ -906,19 +907,13 @@ void GrVkGpu::generateMipmap(GrVkTexture* tex, GrSurfaceOrigin texOrigin) { if (!caps.configCanBeDstofBlit(tex->config(), false) || !caps.configCanBeSrcofBlit(tex->config(), false) || !caps.mipMapSupport()) { - return; + return false; } if (this->vkCaps().mustSubmitCommandsBeforeCopyOp()) { this->submitCommandBuffer(kSkip_SyncQueue); } - // We may need to resolve the texture first if it is also a render target - GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(tex->asRenderTarget()); - if (texRT) { - this->internalResolveRenderTarget(texRT, false); - } - int width = tex->width(); int height = tex->height(); VkImageBlit blitRegion; @@ -926,26 +921,26 @@ void GrVkGpu::generateMipmap(GrVkTexture* tex, GrSurfaceOrigin texOrigin) { // SkMipMap doesn't include the base level in the level count so we have to add 1 uint32_t levelCount = SkMipMap::ComputeLevelCount(tex->width(), tex->height()) + 1; - SkASSERT(levelCount == tex->mipLevels()); + SkASSERT(levelCount == vkTex->mipLevels()); // change layout of the layers so we can write to them. - tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, false); + vkTex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, false); // setup memory barrier - SkASSERT(GrVkFormatIsSupported(tex->imageFormat())); + SkASSERT(GrVkFormatIsSupported(vkTex->imageFormat())); VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; VkImageMemoryBarrier imageMemoryBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType - nullptr, // pNext - VK_ACCESS_TRANSFER_WRITE_BIT, // srcAccessMask - VK_ACCESS_TRANSFER_READ_BIT, // dstAccessMask - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // oldLayout - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // newLayout - VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex - VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex - tex->image(), // image - { aspectFlags, 0, 1, 0, 1 } // subresourceRange + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType + nullptr, // pNext + VK_ACCESS_TRANSFER_WRITE_BIT, // srcAccessMask + VK_ACCESS_TRANSFER_READ_BIT, // dstAccessMask + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // oldLayout + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // newLayout + VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex + VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex + vkTex->image(), // image + {aspectFlags, 0, 1, 0, 1} // subresourceRange }; // Blit the miplevels @@ -967,11 +962,11 @@ void GrVkGpu::generateMipmap(GrVkTexture* tex, GrSurfaceOrigin texOrigin) { blitRegion.dstOffsets[0] = { 0, 0, 0 }; blitRegion.dstOffsets[1] = { width, height, 1 }; fCurrentCmdBuffer->blitImage(this, - tex->resource(), - tex->image(), + vkTex->resource(), + vkTex->image(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - tex->resource(), - tex->image(), + vkTex->resource(), + vkTex->image(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blitRegion, @@ -984,7 +979,8 @@ void GrVkGpu::generateMipmap(GrVkTexture* tex, GrSurfaceOrigin texOrigin) { imageMemoryBarrier.subresourceRange.baseMipLevel = mipLevel - 1; this->addImageMemoryBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, false, &imageMemoryBarrier); - tex->updateImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + vkTex->updateImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + return true; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h index 5df1675794..052476098d 100644 --- a/src/gpu/vk/GrVkGpu.h +++ b/src/gpu/vk/GrVkGpu.h @@ -114,6 +114,8 @@ public: return fCompiler; } + bool onRegenerateMipMapLevels(GrTexture* tex) override; + void onResolveRenderTarget(GrRenderTarget* target) override { this->internalResolveRenderTarget(target, true); } @@ -137,8 +139,6 @@ public: sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override; - void generateMipmap(GrVkTexture* tex, GrSurfaceOrigin texOrigin); - void copyBuffer(GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size); bool updateBuffer(GrVkBuffer* buffer, const void* src, VkDeviceSize offset, VkDeviceSize size); diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp index e28a532bbb..0058a948fe 100644 --- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp +++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp @@ -622,8 +622,7 @@ static void prepare_sampled_images(const GrResourceIOProcessor& processor, if (GrSamplerState::Filter::kMipMap == sampler.samplerState().filter()) { SkASSERT(vkTexture->texturePriv().mipMapped() == GrMipMapped::kYes); if (vkTexture->texturePriv().mipMapsAreDirty()) { - gpu->generateMipmap(vkTexture, sampler.proxy()->origin()); - vkTexture->texturePriv().markMipMapsClean(); + gpu->regenerateMipMapLevels(vkTexture); } } sampledImages->push_back(vkTexture); diff --git a/tests/GrTextureMipMapInvalidationTest.cpp b/tests/GrTextureMipMapInvalidationTest.cpp index 8da79c9565..ea2d0de107 100644 --- a/tests/GrTextureMipMapInvalidationTest.cpp +++ b/tests/GrTextureMipMapInvalidationTest.cpp @@ -5,9 +5,8 @@ * found in the LICENSE file. */ -#include "SkTypes.h" - #include "GrContext.h" +#include "GrContextPriv.h" #include "GrTexturePriv.h" #include "SkCanvas.h" #include "SkImage_Base.h" @@ -40,18 +39,65 @@ DEF_GPUTEST_FOR_NULLGL_CONTEXT(GrTextureMipMapInvalidationTest, reporter, ctxInf REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips); // Painting with downscale and medium filter quality should result in mipmap creation + // Flush the context rather than the canvas as flushing the canvas triggers MIP level + // generation. SkPaint paint; paint.setFilterQuality(kMedium_SkFilterQuality); surf2->getCanvas()->scale(0.2f, 0.2f); surf2->getCanvas()->drawImage(surf1->makeImageSnapshot(), 0, 0, &paint); - surf2->getCanvas()->flush(); + context->flush(); REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips); REPORTER_ASSERT(reporter, !allocateMips || !mipsAreDirty(surf1.get())); // Changing the contents of the surface should invalidate the mipmap, but not de-allocate surf1->getCanvas()->drawCircle(128, 128, 100, SkPaint()); - surf1->getCanvas()->flush(); + context->flush(); REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips); REPORTER_ASSERT(reporter, mipsAreDirty(surf1.get())); } } + +DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReimportImageTextureWithMipLevels, reporter, ctxInfo) { + auto* ctx = ctxInfo.grContext(); + if (!ctx->contextPriv().caps()->mipMapSupport()) { + return; + } + static constexpr auto kCreateWithMipMaps = true; + auto surf = SkSurface::MakeRenderTarget( + ctx, SkBudgeted::kYes, + SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType), 1, + kTopLeft_GrSurfaceOrigin, nullptr, kCreateWithMipMaps); + if (!surf) { + return; + } + surf->getCanvas()->drawColor(SK_ColorDKGRAY); + auto img = surf->makeImageSnapshot(); + if (!img) { + return; + } + surf.reset(); + GrBackendTexture btex; + SkImage::BackendTextureReleaseProc texRelease; + if (!SkImage::MakeBackendTextureFromSkImage(ctx, std::move(img), &btex, &texRelease)) { + // Not all backends support stealing textures yet. + // ERRORF(reporter, "Could not turn image into texture"); + return; + } + REPORTER_ASSERT(reporter, btex.hasMipMaps()); + // Reimport the texture as an image and perform a downsampling draw with medium quality which + // should use the upper MIP levels. + img = SkImage::MakeFromTexture(ctx, btex, kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, + kPremul_SkAlphaType, nullptr); + const auto singlePixelInfo = + SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); + surf = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, singlePixelInfo, 1, + kTopLeft_GrSurfaceOrigin, nullptr); + SkPaint paint; + paint.setFilterQuality(kMedium_SkFilterQuality); + surf->getCanvas()->drawImageRect(img, SkRect::MakeWH(1, 1), &paint); + uint32_t pixel; + surf->readPixels(singlePixelInfo, &pixel, sizeof(uint32_t), 0, 0); + REPORTER_ASSERT(reporter, pixel == SkPreMultiplyColor(SK_ColorDKGRAY)); + img.reset(); + texRelease(btex); +} |