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>
This commit is contained in:
parent
2a284de7a5
commit
930f939c48
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -141,6 +141,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.
|
||||
*
|
||||
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,6 +92,8 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onRegenerateMipMapLevels(GrTexture*) override { return true; }
|
||||
|
||||
void onResolveRenderTarget(GrRenderTarget* target) override { return; }
|
||||
|
||||
void onFinishFlush(bool insertedSemaphores) override {}
|
||||
|
@ -113,6 +113,8 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool onRegenerateMipMapLevels(GrTexture*) override { return false; }
|
||||
|
||||
void onResolveRenderTarget(GrRenderTarget* target) override { return; }
|
||||
|
||||
void onFinishFlush(bool insertedSemaphores) override {}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user