Add automatic generation of mipmaps to Vulkan
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1916563002
Review URL: https://codereview.chromium.org/1916563002
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 5b62a37..b0f3acf 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -20,7 +20,7 @@
/**************************************************************************
* GrDrawTargetCaps fields
**************************************************************************/
- fMipMapSupport = false; //TODO: figure this out
+ fMipMapSupport = true; // always available in Vulkan
fNPOTTextureTileSupport = false; //TODO: figure this out
fTwoSidedStencilSupport = false; //TODO: figure this out
fStencilWrapOpsSupport = false; //TODO: figure this out
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index 94d4c9d..5bd43f2 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -260,21 +260,21 @@
}
void GrVkCommandBuffer::blitImage(const GrVkGpu* gpu,
- GrVkImage* srcImage,
+ const GrVkImage::Resource* srcImage,
VkImageLayout srcLayout,
- GrVkImage* dstImage,
+ const GrVkImage::Resource* dstImage,
VkImageLayout dstLayout,
uint32_t blitRegionCount,
const VkImageBlit* blitRegions,
VkFilter filter) {
SkASSERT(fIsActive);
SkASSERT(!fActiveRenderPass);
- this->addResource(srcImage->resource());
- this->addResource(dstImage->resource());
+ this->addResource(srcImage);
+ this->addResource(dstImage);
GR_VK_CALL(gpu->vkInterface(), CmdBlitImage(fCmdBuffer,
- srcImage->textureImage(),
+ srcImage->fImage,
srcLayout,
- dstImage->textureImage(),
+ dstImage->fImage,
dstLayout,
blitRegionCount,
blitRegions,
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index 1b27c55..b2f6ef0 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -127,9 +127,9 @@
const VkImageCopy* copyRegions);
void blitImage(const GrVkGpu* gpu,
- GrVkImage* srcImage,
+ const GrVkImage::Resource* srcImage,
VkImageLayout srcLayout,
- GrVkImage* dstImage,
+ const GrVkImage::Resource* dstImage,
VkImageLayout dstLayout,
uint32_t blitRegionCount,
const VkImageBlit* blitRegions,
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 4d0ecbf..76fe92a 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -469,7 +469,7 @@
// For now we will set the VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT and
// VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT on every texture since we do not know whether or not we
// will be using this texture in some copy or not. Also this assumes, as is the current case,
- // that all render targets in vulkan are also texutres. If we change this practice of setting
+ // that all render targets in vulkan are also textures. If we change this practice of setting
// both bits, we must make sure to set the destination bit if we are uploading srcData to the
// texture.
usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
@@ -478,14 +478,14 @@
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
// This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is
- // requested, this ImageDesc describes the resolved texutre. Therefore we always have samples set
+ // requested, this ImageDesc describes the resolved texture. Therefore we always have samples set
// to 1.
GrVkImage::ImageDesc imageDesc;
imageDesc.fImageType = VK_IMAGE_TYPE_2D;
imageDesc.fFormat = pixelFormat;
imageDesc.fWidth = desc.fWidth;
imageDesc.fHeight = desc.fHeight;
- imageDesc.fLevels = 1;
+ imageDesc.fLevels = 1; // TODO: support miplevels for optimal tiling
imageDesc.fSamples = 1;
imageDesc.fImageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
imageDesc.fUsageFlags = usageFlags;
@@ -606,6 +606,112 @@
return tgt;
}
+void GrVkGpu::generateMipmap(GrVkTexture* tex) const {
+ // don't need to do anything for linearly tiled textures (can't have mipmaps)
+ if (tex->isLinearTiled()) {
+ return;
+ }
+
+ // We cannot generate mipmaps for images that are multisampled.
+ // TODO: does it even make sense for rendertargets in general?
+ if (tex->asRenderTarget() && tex->asRenderTarget()->numColorSamples() > 1) {
+ return;
+ }
+
+ // determine if we can blit to and from this format
+ const GrVkCaps& caps = this->vkCaps();
+ if (!caps.configCanBeDstofBlit(tex->config(), false) ||
+ !caps.configCanBeSrcofBlit(tex->config(), false)) {
+ return;
+ }
+
+ // change the original image's layout
+ VkImageLayout origSrcLayout = tex->currentLayout();
+ VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origSrcLayout);
+ VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+ VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origSrcLayout);
+ VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+
+ tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ srcAccessMask, dstAccessMask, srcStageMask, dstStageMask, false);
+
+ // grab handle to the original image resource
+ const GrVkImage::Resource* oldResource = tex->resource();
+ oldResource->ref();
+
+ if (!tex->reallocForMipmap(this)) {
+ oldResource->unref(this);
+ return;
+ }
+
+ // change the new image's layout
+ VkImageLayout origDstLayout = tex->currentLayout();
+
+ srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout);
+ dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+ srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);
+ dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ tex->setImageLayout(this,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ srcAccessMask,
+ dstAccessMask,
+ srcStageMask,
+ dstStageMask,
+ false);
+
+ // Blit original image
+ int width = tex->width();
+ int height = tex->height();
+ uint32_t mipLevel = 0;
+
+ VkImageBlit blitRegion;
+ memset(&blitRegion, 0, sizeof(VkImageBlit));
+ blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ blitRegion.srcOffsets[0] = { 0, 0, 0 };
+ blitRegion.srcOffsets[1] = { width, height, 0 };
+ blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 0, 1 };
+ blitRegion.dstOffsets[0] = { 0, 0, 0 };
+ blitRegion.dstOffsets[1] = { width, height, 0 };
+
+ fCurrentCmdBuffer->blitImage(this,
+ oldResource,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ tex->resource(),
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ 1,
+ &blitRegion,
+ VK_FILTER_LINEAR);
+ // Blit the miplevels
+ while (width/2 > 0 && height/2 > 0) {
+ blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 0, 1 };
+ blitRegion.srcOffsets[0] = { 0, 0, 0 };
+ blitRegion.srcOffsets[1] = { width, height, 0 };
+ blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel+1, 0, 1 };
+ blitRegion.dstOffsets[0] = { 0, 0, 0 };
+ blitRegion.dstOffsets[1] = { width/2, height/2, 0 };
+
+ fCurrentCmdBuffer->blitImage(this,
+ tex->resource(),
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ tex->resource(),
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ 1,
+ &blitRegion,
+ VK_FILTER_LINEAR);
+
+ width /= 2;
+ height /= 2;
+ mipLevel++;
+ }
+
+ oldResource->unref(this);
+}
+
+
+
////////////////////////////////////////////////////////////////////////////////
void GrVkGpu::bindGeometry(const GrPrimitiveProcessor& primProc,
@@ -1268,9 +1374,9 @@
blitRegion.dstOffsets[1] = { dstRect.fRight, dstRect.fBottom, 0 };
fCurrentCmdBuffer->blitImage(this,
- srcImage,
+ srcImage->resource(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- dstImage,
+ dstImage->resource(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&blitRegion,
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index da9d8b6..9c8a48c 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -111,6 +111,8 @@
void finishDrawTarget() override;
+ void generateMipmap(GrVkTexture* tex) const;
+
private:
GrVkGpu(GrContext* context, const GrContextOptions& options,
const GrVkBackendContext* backendContext);
diff --git a/src/gpu/vk/GrVkImageView.cpp b/src/gpu/vk/GrVkImageView.cpp
index 1ab2475..d94aeec 100644
--- a/src/gpu/vk/GrVkImageView.cpp
+++ b/src/gpu/vk/GrVkImageView.cpp
@@ -9,8 +9,8 @@
#include "GrVkGpu.h"
#include "GrVkUtil.h"
-const GrVkImageView* GrVkImageView::Create(GrVkGpu* gpu, VkImage image, VkFormat format,
- Type viewType) {
+const GrVkImageView* GrVkImageView::Create(const GrVkGpu* gpu, VkImage image, VkFormat format,
+ Type viewType, uint32_t miplevels) {
VkImageView imageView;
// Create the VkImageView
@@ -23,7 +23,7 @@
format, // format
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }, // components
- { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, // subresourceRange
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0, miplevels, 0, 1 }, // subresourceRange
};
if (kStencil_Type == viewType) {
viewInfo.components.r = VK_COMPONENT_SWIZZLE_ZERO;
diff --git a/src/gpu/vk/GrVkImageView.h b/src/gpu/vk/GrVkImageView.h
index f700808..4be0d19 100644
--- a/src/gpu/vk/GrVkImageView.h
+++ b/src/gpu/vk/GrVkImageView.h
@@ -21,7 +21,8 @@
kStencil_Type
};
- static const GrVkImageView* Create(GrVkGpu* gpu, VkImage image, VkFormat format, Type viewType);
+ static const GrVkImageView* Create(const GrVkGpu* gpu, VkImage image, VkFormat format,
+ Type viewType, uint32_t miplevels);
VkImageView imageView() const { return fImageView; }
diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp
index 0194e29..4fe2929 100644
--- a/src/gpu/vk/GrVkPipelineState.cpp
+++ b/src/gpu/vk/GrVkPipelineState.cpp
@@ -8,6 +8,7 @@
#include "GrVkPipelineState.h"
#include "GrPipeline.h"
+#include "GrTexturePriv.h"
#include "GrVkCommandBuffer.h"
#include "GrVkDescriptorPool.h"
#include "GrVkGpu.h"
@@ -21,6 +22,7 @@
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLXferProcessor.h"
+#include "SkMipmap.h"
GrVkPipelineState::GrVkPipelineState(GrVkGpu* gpu,
const GrVkPipelineState::Desc& desc,
@@ -290,9 +292,17 @@
for (int i = 0; i < textureBindings.count(); ++i) {
const GrTextureParams& params = textureBindings[i]->getParams();
- fSamplers.push(gpu->resourceProvider().findOrCreateCompatibleSampler(params));
GrVkTexture* texture = static_cast<GrVkTexture*>(textureBindings[i]->getTexture());
+ if (GrTextureParams::kMipMap_FilterMode == params.filterMode()) {
+ if (texture->texturePriv().mipMapsAreDirty()) {
+ gpu->generateMipmap(texture);
+ texture->texturePriv().dirtyMipMaps(false);
+ }
+ }
+
+ fSamplers.push(gpu->resourceProvider().findOrCreateCompatibleSampler(params,
+ texture->texturePriv().maxMipMapLevel()));
const GrVkImage::Resource* textureResource = texture->resource();
textureResource->ref();
diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp
index 8ad3968..46099f2 100644
--- a/src/gpu/vk/GrVkRenderTarget.cpp
+++ b/src/gpu/vk/GrVkRenderTarget.cpp
@@ -145,7 +145,7 @@
// Create Resolve attachment view
resolveAttachmentView = GrVkImageView::Create(gpu, imageResource->fImage, pixelFormat,
- GrVkImageView::kColor_Type);
+ GrVkImageView::kColor_Type, 1);
if (!resolveAttachmentView) {
msaaResource->unref(gpu);
return nullptr;
@@ -157,7 +157,7 @@
// Get color attachment view
const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat,
- GrVkImageView::kColor_Type);
+ GrVkImageView::kColor_Type, 1);
if (!colorAttachmentView) {
if (msaaResource) {
resolveAttachmentView->unref(gpu);
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index 7def55d..8ba5ade 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -85,10 +85,11 @@
return new GrVkDescriptorPool(fGpu, type, count);
}
-GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrTextureParams& params) {
- GrVkSampler* sampler = fSamplers.find(GrVkSampler::GenerateKey(params));
+GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrTextureParams& params,
+ uint32_t mipLevels) {
+ GrVkSampler* sampler = fSamplers.find(GrVkSampler::GenerateKey(params, mipLevels));
if (!sampler) {
- sampler = GrVkSampler::Create(fGpu, params);
+ sampler = GrVkSampler::Create(fGpu, params, mipLevels);
fSamplers.add(sampler);
}
SkASSERT(sampler);
@@ -136,7 +137,7 @@
fSimpleRenderPasses.reset();
// Iterate through all store GrVkSamplers and unref them before resetting the hash.
- SkTDynamicHash<GrVkSampler, uint8_t>::Iter iter(&fSamplers);
+ SkTDynamicHash<GrVkSampler, uint16_t>::Iter iter(&fSamplers);
for (; !iter.done(); ++iter) {
(*iter).unref(fGpu);
}
@@ -166,7 +167,7 @@
fSimpleRenderPasses.reset();
// Iterate through all store GrVkSamplers and unrefAndAbandon them before resetting the hash.
- SkTDynamicHash<GrVkSampler, uint8_t>::Iter iter(&fSamplers);
+ SkTDynamicHash<GrVkSampler, uint16_t>::Iter iter(&fSamplers);
for (; !iter.done(); ++iter) {
(*iter).unrefAndAbandon();
}
diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h
index 1fdf144..4853bf1 100644
--- a/src/gpu/vk/GrVkResourceProvider.h
+++ b/src/gpu/vk/GrVkResourceProvider.h
@@ -63,7 +63,7 @@
// Finds or creates a compatible GrVkSampler based on the GrTextureParams.
// The refcount is incremented and a pointer returned.
- GrVkSampler* findOrCreateCompatibleSampler(const GrTextureParams&);
+ GrVkSampler* findOrCreateCompatibleSampler(const GrTextureParams&, uint32_t mipLevels);
sk_sp<GrVkPipelineState> findOrCreateCompatiblePipelineState(const GrPipeline&,
const GrPrimitiveProcessor&,
@@ -136,7 +136,7 @@
// Stores GrVkSampler objects that we've already created so we can reuse them across multiple
// GrVkPipelineStates
- SkTDynamicHash<GrVkSampler, uint8_t> fSamplers;
+ SkTDynamicHash<GrVkSampler, uint16_t> fSamplers;
// Cache of GrVkPipelineStates
PipelineStateCache* fPipelineStateCache;
diff --git a/src/gpu/vk/GrVkSampler.cpp b/src/gpu/vk/GrVkSampler.cpp
index 75c2ee8..904a8b7 100644
--- a/src/gpu/vk/GrVkSampler.cpp
+++ b/src/gpu/vk/GrVkSampler.cpp
@@ -23,7 +23,8 @@
return gWrapModes[tm];
}
-GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrTextureParams& params) {
+GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrTextureParams& params,
+ uint32_t mipLevels) {
static VkFilter vkMinFilterModes[] = {
VK_FILTER_NEAREST,
@@ -58,7 +59,7 @@
// level mip). If the filters weren't the same we could set min = 0 and max = 0.25 to force
// the minFilter on mip level 0.
createInfo.minLod = 0.0f;
- createInfo.maxLod = 0.0f;
+ createInfo.maxLod = (mipLevels == 1) ? 0.0f : (float)(mipLevels);
createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
createInfo.unnormalizedCoordinates = VK_FALSE;
@@ -68,7 +69,7 @@
nullptr,
&sampler));
- return new GrVkSampler(sampler, GenerateKey(params));
+ return new GrVkSampler(sampler, GenerateKey(params, mipLevels));
}
void GrVkSampler::freeGPUData(const GrVkGpu* gpu) const {
@@ -76,15 +77,21 @@
GR_VK_CALL(gpu->vkInterface(), DestroySampler(gpu->device(), fSampler, nullptr));
}
-uint8_t GrVkSampler::GenerateKey(const GrTextureParams& params) {
+uint16_t GrVkSampler::GenerateKey(const GrTextureParams& params, uint32_t mipLevels) {
+ const int kTileModeXShift = 2;
+ const int kTileModeYShift = 4;
+ const int kMipLevelShift = 6;
- uint8_t key = params.filterMode();
+ uint16_t key = params.filterMode();
SkASSERT(params.filterMode() <= 3);
- key |= (params.getTileModeX() << 2);
+ key |= (params.getTileModeX() << kTileModeXShift);
GR_STATIC_ASSERT(SkShader::kTileModeCount <= 4);
- key |= (params.getTileModeY() << 4);
+ key |= (params.getTileModeY() << kTileModeYShift);
+
+ SkASSERT(mipLevels < 1024);
+ key |= (mipLevels << kMipLevelShift);
return key;
}
diff --git a/src/gpu/vk/GrVkSampler.h b/src/gpu/vk/GrVkSampler.h
index ec97751..2aa5017 100644
--- a/src/gpu/vk/GrVkSampler.h
+++ b/src/gpu/vk/GrVkSampler.h
@@ -19,22 +19,22 @@
class GrVkSampler : public GrVkResource {
public:
- static GrVkSampler* Create(const GrVkGpu* gpu, const GrTextureParams&);
+ static GrVkSampler* Create(const GrVkGpu* gpu, const GrTextureParams&, uint32_t mipLevels);
VkSampler sampler() const { return fSampler; }
// Helpers for hashing GrVkSampler
- static uint8_t GenerateKey(const GrTextureParams&);
+ static uint16_t GenerateKey(const GrTextureParams&, uint32_t mipLevels);
- static const uint8_t& GetKey(const GrVkSampler& sampler) { return sampler.fKey; }
- static uint32_t Hash(const uint8_t& key) { return key; }
+ static const uint16_t& GetKey(const GrVkSampler& sampler) { return sampler.fKey; }
+ static uint32_t Hash(const uint16_t& key) { return key; }
private:
- GrVkSampler(VkSampler sampler, uint8_t key) : INHERITED(), fSampler(sampler), fKey(key) {}
+ GrVkSampler(VkSampler sampler, uint16_t key) : INHERITED(), fSampler(sampler), fKey(key) {}
void freeGPUData(const GrVkGpu* gpu) const override;
VkSampler fSampler;
- uint8_t fKey;
+ uint16_t fKey;
typedef GrVkResource INHERITED;
};
diff --git a/src/gpu/vk/GrVkStencilAttachment.cpp b/src/gpu/vk/GrVkStencilAttachment.cpp
index 3af5488..a876aea 100644
--- a/src/gpu/vk/GrVkStencilAttachment.cpp
+++ b/src/gpu/vk/GrVkStencilAttachment.cpp
@@ -51,7 +51,7 @@
const GrVkImageView* imageView = GrVkImageView::Create(gpu, imageResource->fImage,
format.fInternalFormat,
- GrVkImageView::kStencil_Type);
+ GrVkImageView::kStencil_Type, 1);
if (!imageView) {
imageResource->unref(gpu);
return nullptr;
diff --git a/src/gpu/vk/GrVkTexture.cpp b/src/gpu/vk/GrVkTexture.cpp
index cdbc84f..736d8e3 100644
--- a/src/gpu/vk/GrVkTexture.cpp
+++ b/src/gpu/vk/GrVkTexture.cpp
@@ -8,7 +8,9 @@
#include "GrVkTexture.h"
#include "GrVkGpu.h"
#include "GrVkImageView.h"
+#include "GrTexturePriv.h"
#include "GrVkUtil.h"
+#include "SkMipmap.h"
#include "vk/GrVkTypes.h"
@@ -60,8 +62,14 @@
VkFormat format,
const GrVkImage::Resource* imageResource) {
VkImage image = imageResource->fImage;
+
+ uint32_t mipLevels = 1;
+ // TODO: enable when mipLevel loading is implemented in GrVkGpu
+ //if (desc.fIsMipMapped) {
+ // mipLevels = SkMipMap::ComputeLevelCount(this->width(), this->height());
+ //}
const GrVkImageView* imageView = GrVkImageView::Create(gpu, image, format,
- GrVkImageView::kColor_Type);
+ GrVkImageView::kColor_Type, mipLevels);
if (!imageView) {
return nullptr;
}
@@ -157,3 +165,56 @@
SkASSERT(!this->wasDestroyed());
return static_cast<GrVkGpu*>(this->getGpu());
}
+
+bool GrVkTexture::reallocForMipmap(const GrVkGpu* gpu) {
+ const GrVkImage::Resource* oldResource = fResource;
+
+ // Does this even make sense for rendertargets?
+ bool renderTarget = SkToBool(fDesc.fFlags & kRenderTarget_GrSurfaceFlag);
+
+ VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
+ if (renderTarget) {
+ usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+ usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+
+ uint32_t mipLevels = SkMipMap::ComputeLevelCount(this->width(), this->height());
+ if (mipLevels == 1) {
+ // don't need to do anything for a 1x1 texture
+ return false;
+ }
+
+ GrVkImage::ImageDesc imageDesc;
+ imageDesc.fImageType = VK_IMAGE_TYPE_2D;
+ imageDesc.fFormat = oldResource->fFormat;
+ imageDesc.fWidth = fDesc.fWidth;
+ imageDesc.fHeight = fDesc.fHeight;
+ imageDesc.fLevels = mipLevels;
+ imageDesc.fSamples = 1;
+ imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
+ imageDesc.fUsageFlags = usageFlags;
+ imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+
+ const GrVkImage::Resource* imageResource = GrVkImage::CreateResource(gpu, imageDesc);
+ if (!imageResource) {
+ return false;
+ }
+
+ // have to create a new image view for new resource
+ const GrVkImageView* oldView = fTextureView;
+ VkImage image = imageResource->fImage;
+ const GrVkImageView* textureView = GrVkImageView::Create(gpu, image, imageResource->fFormat,
+ GrVkImageView::kColor_Type, mipLevels);
+ if (!textureView) {
+ imageResource->unref(gpu);
+ return false;
+ }
+
+ oldResource->unref(gpu);
+ oldView->unref(gpu);
+ fResource = imageResource;
+ fTextureView = textureView;
+ this->texturePriv().setMaxMipMapLevel(mipLevels);
+
+ return true;
+}
diff --git a/src/gpu/vk/GrVkTexture.h b/src/gpu/vk/GrVkTexture.h
index 936eeb7..a5e82e8 100644
--- a/src/gpu/vk/GrVkTexture.h
+++ b/src/gpu/vk/GrVkTexture.h
@@ -33,6 +33,8 @@
const GrVkImageView* textureView() const { return fTextureView; }
+ bool reallocForMipmap(const GrVkGpu* gpu);
+
protected:
GrVkTexture(GrVkGpu*, const GrSurfaceDesc&,
const GrVkImage::Resource*, const GrVkImageView* imageView);
diff --git a/src/gpu/vk/GrVkTextureRenderTarget.cpp b/src/gpu/vk/GrVkTextureRenderTarget.cpp
index 6bfdf3e..6742a91 100644
--- a/src/gpu/vk/GrVkTextureRenderTarget.cpp
+++ b/src/gpu/vk/GrVkTextureRenderTarget.cpp
@@ -12,6 +12,8 @@
#include "GrVkImageView.h"
#include "GrVkUtil.h"
+#include "SkMipmap.h"
+
#include "vk/GrVkTypes.h"
#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
@@ -24,8 +26,13 @@
const GrVkImage::Resource* imageResource) {
VkImage image = imageResource->fImage;
// Create the texture ImageView
+ uint32_t mipLevels = 1;
+ //TODO: does a mipmapped textureRenderTarget make sense?
+ //if (desc.fIsMipMapped) {
+ // mipLevels = SkMipMap::ComputeLevelCount(this->width(), this->height());
+ //}
const GrVkImageView* imageView = GrVkImageView::Create(gpu, image, format,
- GrVkImageView::kColor_Type);
+ GrVkImageView::kColor_Type, mipLevels);
if (!imageView) {
return nullptr;
}
@@ -67,7 +74,7 @@
resolveAttachmentView->ref();
} else {
resolveAttachmentView = GrVkImageView::Create(gpu, image, pixelFormat,
- GrVkImageView::kColor_Type);
+ GrVkImageView::kColor_Type, 1);
if (!resolveAttachmentView) {
msaaImageResource->unref(gpu);
imageView->unref(gpu);
@@ -88,7 +95,7 @@
colorAttachmentView->ref();
} else {
colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat,
- GrVkImageView::kColor_Type);
+ GrVkImageView::kColor_Type, 1);
if (!colorAttachmentView) {
if (msaaImageResource) {
resolveAttachmentView->unref(gpu);