aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar egdaniel <egdaniel@google.com>2016-09-27 08:00:53 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-09-27 08:00:53 -0700
commitbc9b2963bf9e39c47ae5c3ab94b8503b476f4f0e (patch)
treedd1fe0200d6191882ffb251d1a150f32f418b3cd /src
parentcefee07bf7c5f8ae3016d8c00674f078c2fdb592 (diff)
Add GrVkCopyPipeline to handle vulkan copies as draws
Diffstat (limited to 'src')
-rw-r--r--src/gpu/vk/GrVkCaps.cpp1
-rw-r--r--src/gpu/vk/GrVkCaps.h7
-rw-r--r--src/gpu/vk/GrVkCommandBuffer.cpp26
-rw-r--r--src/gpu/vk/GrVkCommandBuffer.h10
-rw-r--r--src/gpu/vk/GrVkCopyManager.cpp409
-rw-r--r--src/gpu/vk/GrVkCopyManager.h55
-rw-r--r--src/gpu/vk/GrVkGpu.cpp20
-rw-r--r--src/gpu/vk/GrVkGpu.h7
-rw-r--r--src/gpu/vk/GrVkGpuCommandBuffer.cpp6
-rw-r--r--src/gpu/vk/GrVkMemory.cpp2
-rw-r--r--src/gpu/vk/GrVkPipelineStateBuilder.cpp1
-rw-r--r--src/gpu/vk/GrVkResourceProvider.cpp34
-rw-r--r--src/gpu/vk/GrVkResourceProvider.h8
-rw-r--r--src/gpu/vk/GrVkUtil.cpp2
14 files changed, 576 insertions, 12 deletions
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index be25c889e3..7669ba541a 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -18,6 +18,7 @@ GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface*
fCanUseGLSLForShaderModule = false;
fMustDoCopiesFromOrigin = false;
fAllowInitializationErrorOnTearDown = false;
+ fSupportsCopiesAsDraws = false;
/**************************************************************************
* GrDrawTargetCaps fields
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index 6f46952f43..8e8953e522 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -70,6 +70,10 @@ public:
return fAllowInitializationErrorOnTearDown;
}
+ bool supportsCopiesAsDraws() const {
+ return fSupportsCopiesAsDraws;
+ }
+
/**
* Returns both a supported and most prefered stencil format to use in draws.
*/
@@ -128,6 +132,9 @@ private:
// flag says we will accept VK_ERROR_INITIALIZATION_FAILED as well.
bool fAllowInitializationErrorOnTearDown;
+ // Check whether we support using draws for copies.
+ bool fSupportsCopiesAsDraws;
+
typedef GrCaps INHERITED;
};
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index 41a7bb51d7..bc6272c0c6 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -190,6 +190,32 @@ void GrVkCommandBuffer::bindDescriptorSets(const GrVkGpu* gpu,
pipelineState->addUniformResources(*this);
}
+void GrVkCommandBuffer::bindDescriptorSets(const GrVkGpu* gpu,
+ const SkTArray<const GrVkRecycledResource*>& recycled,
+ const SkTArray<const GrVkResource*>& resources,
+ VkPipelineLayout layout,
+ uint32_t firstSet,
+ uint32_t setCount,
+ const VkDescriptorSet* descriptorSets,
+ uint32_t dynamicOffsetCount,
+ const uint32_t* dynamicOffsets) {
+ SkASSERT(fIsActive);
+ GR_VK_CALL(gpu->vkInterface(), CmdBindDescriptorSets(fCmdBuffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ layout,
+ firstSet,
+ setCount,
+ descriptorSets,
+ dynamicOffsetCount,
+ dynamicOffsets));
+ for (int i = 0; i < recycled.count(); ++i) {
+ this->addRecycledResource(recycled[i]);
+ }
+ for (int i = 0; i < resources.count(); ++i) {
+ this->addResource(resources[i]);
+ }
+}
+
void GrVkCommandBuffer::bindPipeline(const GrVkGpu* gpu, const GrVkPipeline* pipeline) {
SkASSERT(fIsActive);
GR_VK_CALL(gpu->vkInterface(), CmdBindPipeline(fCmdBuffer,
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index e593b2d542..9864ec02fe 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -78,6 +78,16 @@ public:
uint32_t dynamicOffsetCount,
const uint32_t* dynamicOffsets);
+ void bindDescriptorSets(const GrVkGpu* gpu,
+ const SkTArray<const GrVkRecycledResource*>&,
+ const SkTArray<const GrVkResource*>&,
+ VkPipelineLayout layout,
+ uint32_t firstSet,
+ uint32_t setCount,
+ const VkDescriptorSet* descriptorSets,
+ uint32_t dynamicOffsetCount,
+ const uint32_t* dynamicOffsets);
+
void setViewport(const GrVkGpu* gpu,
uint32_t firstViewport,
uint32_t viewportCount,
diff --git a/src/gpu/vk/GrVkCopyManager.cpp b/src/gpu/vk/GrVkCopyManager.cpp
new file mode 100644
index 0000000000..293863d002
--- /dev/null
+++ b/src/gpu/vk/GrVkCopyManager.cpp
@@ -0,0 +1,409 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+*/
+
+#include "GrVkCopyManager.h"
+
+#include "GrSurface.h"
+#include "GrTextureParams.h"
+#include "GrTexturePriv.h"
+#include "GrVkCommandBuffer.h"
+#include "GrVkCopyPipeline.h"
+#include "GrVkDescriptorSet.h"
+#include "GrVkGpu.h"
+#include "GrVkImageView.h"
+#include "GrVkRenderTarget.h"
+#include "GrVkResourceProvider.h"
+#include "GrVkSampler.h"
+#include "GrVkTexture.h"
+#include "GrVkUniformBuffer.h"
+#include "GrVkVertexBuffer.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+
+bool GrVkCopyManager::createCopyProgram(GrVkGpu* gpu) {
+ const GrGLSLCaps* glslCaps = gpu->vkCaps().glslCaps();
+ const char* version = glslCaps->versionDeclString();
+ SkString vertShaderText(version);
+ vertShaderText.append(
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+
+ "layout(set = 0, binding = 0) uniform vertexUniformBuffer {"
+ "mediump vec4 uPosXform;"
+ "mediump vec4 uTexCoordXform;"
+ "};"
+ "layout(location = 0) in highp vec2 inPosition;"
+ "layout(location = 1) out mediump vec2 vTexCoord;"
+
+ "// Copy Program VS\n"
+ "void main() {"
+ "vTexCoord = inPosition * uTexCoordXform.xy + uTexCoordXform.zw;"
+ "gl_Position.xy = inPosition * uPosXform.xy + uPosXform.zw;"
+ "gl_Position.zw = vec2(0, 1);"
+ "}"
+ );
+
+ SkString fragShaderText(version);
+ fragShaderText.append(
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+
+ "precision mediump float;"
+
+ "layout(set = 1, binding = 0) uniform mediump sampler2D uTextureSampler;"
+ "layout(location = 1) in mediump vec2 vTexCoord;"
+ "layout(location = 0, index = 0) out mediump vec4 fsColorOut;"
+
+ "// Copy Program FS\n"
+ "void main() {"
+ "fsColorOut = texture(uTextureSampler, vTexCoord);"
+ "}"
+ );
+
+ if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(),
+ VK_SHADER_STAGE_VERTEX_BIT,
+ &fVertShaderModule, &fShaderStageInfo[0])) {
+ this->destroyResources(gpu);
+ return false;
+ }
+
+ if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(),
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ &fFragShaderModule, &fShaderStageInfo[1])) {
+ this->destroyResources(gpu);
+ return false;
+ }
+
+ VkDescriptorSetLayout dsLayout[2];
+
+ GrVkResourceProvider& resourceProvider = gpu->resourceProvider();
+
+ dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout();
+
+ uint32_t samplerVisibility = kFragment_GrShaderFlag;
+ SkTArray<uint32_t> visibilityArray(&samplerVisibility, 1);
+
+ resourceProvider.getSamplerDescriptorSetHandle(visibilityArray, &fSamplerDSHandle);
+ dsLayout[GrVkUniformHandler::kSamplerDescSet] =
+ resourceProvider.getSamplerDSLayout(fSamplerDSHandle);
+
+ // Create the VkPipelineLayout
+ VkPipelineLayoutCreateInfo layoutCreateInfo;
+ memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags));
+ layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ layoutCreateInfo.pNext = 0;
+ layoutCreateInfo.flags = 0;
+ layoutCreateInfo.setLayoutCount = 2;
+ layoutCreateInfo.pSetLayouts = dsLayout;
+ layoutCreateInfo.pushConstantRangeCount = 0;
+ layoutCreateInfo.pPushConstantRanges = nullptr;
+
+ VkResult err = GR_VK_CALL(gpu->vkInterface(), CreatePipelineLayout(gpu->device(),
+ &layoutCreateInfo,
+ nullptr,
+ &fPipelineLayout));
+ if (err) {
+ this->destroyResources(gpu);
+ return false;
+ }
+
+ static const float vdata[] = {
+ 0, 0,
+ 0, 1,
+ 1, 0,
+ 1, 1
+ };
+ fVertexBuffer.reset(GrVkVertexBuffer::Create(gpu, sizeof(vdata), false));
+ SkASSERT(fVertexBuffer.get());
+ fVertexBuffer->updateData(vdata, sizeof(vdata));
+
+ // We use 2 vec4's for uniforms
+ fUniformBuffer = GrVkUniformBuffer::Create(gpu, 8 * sizeof(float));
+ SkASSERT(fUniformBuffer);
+
+ return true;
+}
+
+bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu,
+ GrSurface* dst,
+ GrSurface* src,
+ const SkIRect& srcRect,
+ const SkIPoint& dstPoint) {
+ if (!gpu->vkCaps().supportsCopiesAsDraws()) {
+ return false;
+ }
+
+ GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(dst->asRenderTarget());
+ if (!rt) {
+ return false;
+ }
+
+ GrVkTexture* srcTex = static_cast<GrVkTexture*>(src->asTexture());
+ if (!srcTex) {
+ return false;
+ }
+
+ if (VK_NULL_HANDLE == fVertShaderModule) {
+ SkASSERT(VK_NULL_HANDLE == fFragShaderModule &&
+ VK_NULL_HANDLE == fPipelineLayout &&
+ nullptr == fVertexBuffer.get() &&
+ nullptr == fUniformBuffer);
+ if (!this->createCopyProgram(gpu)) {
+ SkDebugf("Failed to create copy program.\n");
+ return false;
+ }
+ }
+
+ GrVkResourceProvider& resourceProv = gpu->resourceProvider();
+
+ GrVkCopyPipeline* pipeline = resourceProv.findOrCreateCopyPipeline(rt,
+ fShaderStageInfo,
+ fPipelineLayout);
+ if (!pipeline) {
+ return false;
+ }
+
+ // UPDATE UNIFORM DESCRIPTOR SET
+ int w = srcRect.width();
+ int h = srcRect.height();
+
+ // dst rect edges in NDC (-1 to 1)
+ int dw = dst->width();
+ int dh = dst->height();
+ float dx0 = 2.f * dstPoint.fX / dw - 1.f;
+ float dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f;
+ float dy0 = 2.f * dstPoint.fY / dh - 1.f;
+ float dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f;
+ if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
+ dy0 = -dy0;
+ dy1 = -dy1;
+ }
+
+
+ float sx0 = (float)srcRect.fLeft;
+ float sx1 = (float)(srcRect.fLeft + w);
+ float sy0 = (float)srcRect.fTop;
+ float sy1 = (float)(srcRect.fTop + h);
+ int sh = src->height();
+ if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
+ sy0 = sh - sy0;
+ sy1 = sh - sy1;
+ }
+ // src rect edges in normalized texture space (0 to 1).
+ int sw = src->width();
+ sx0 /= sw;
+ sx1 /= sw;
+ sy0 /= sh;
+ sy1 /= sh;
+
+ float uniData[] = { dx1 - dx0, dy1 - dy0, dx0, dy0, // posXform
+ sx1 - sx0, sy1 - sy0, sx0, sy0 }; // texCoordXform
+
+ fUniformBuffer->updateData(gpu, uniData, sizeof(uniData), nullptr);
+
+ const GrVkDescriptorSet* uniformDS = resourceProv.getUniformDescriptorSet();
+ SkASSERT(uniformDS);
+
+ VkDescriptorBufferInfo uniBufferInfo;
+ uniBufferInfo.buffer = fUniformBuffer->buffer();
+ uniBufferInfo.offset = fUniformBuffer->offset();
+ uniBufferInfo.range = fUniformBuffer->size();
+
+ VkWriteDescriptorSet descriptorWrites;
+ descriptorWrites.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrites.pNext = nullptr;
+ descriptorWrites.dstSet = uniformDS->descriptorSet();
+ descriptorWrites.dstBinding = GrVkUniformHandler::kVertexBinding;
+ descriptorWrites.dstArrayElement = 0;
+ descriptorWrites.descriptorCount = 1;
+ descriptorWrites.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descriptorWrites.pImageInfo = nullptr;
+ descriptorWrites.pBufferInfo = &uniBufferInfo;
+ descriptorWrites.pTexelBufferView = nullptr;
+
+ GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
+ 1,
+ &descriptorWrites,
+ 0, nullptr));
+
+ // UPDATE SAMPLER DESCRIPTOR SET
+ const GrVkDescriptorSet* samplerDS =
+ gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle);
+
+ GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
+
+ GrVkSampler* sampler =
+ resourceProv.findOrCreateCompatibleSampler(params, srcTex->texturePriv().maxMipMapLevel());
+
+ VkDescriptorImageInfo imageInfo;
+ memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
+ imageInfo.sampler = sampler->sampler();
+ imageInfo.imageView = srcTex->textureView(true)->imageView();
+ imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ VkWriteDescriptorSet writeInfo;
+ memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet));
+ writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ writeInfo.pNext = nullptr;
+ writeInfo.dstSet = samplerDS->descriptorSet();
+ writeInfo.dstBinding = 0;
+ writeInfo.dstArrayElement = 0;
+ writeInfo.descriptorCount = 1;
+ writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ writeInfo.pImageInfo = &imageInfo;
+ writeInfo.pBufferInfo = nullptr;
+ writeInfo.pTexelBufferView = nullptr;
+
+ GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
+ 1,
+ &writeInfo,
+ 0, nullptr));
+
+ VkDescriptorSet vkDescSets[] = { uniformDS->descriptorSet(), samplerDS->descriptorSet() };
+
+ GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(srcTex->asRenderTarget());
+ if (texRT) {
+ gpu->onResolveRenderTarget(texRT);
+ }
+
+ GrVkPrimaryCommandBuffer* cmdBuffer = gpu->currentCommandBuffer();
+
+ // TODO: Make tighter bounds and then adjust bounds for origin and granularity if we see
+ // any perf issues with using the whole bounds
+ SkIRect bounds = SkIRect::MakeWH(rt->width(), rt->height());
+
+ // Change layouts of rt and texture
+ GrVkImage* targetImage = rt->msaaImage() ? rt->msaaImage() : rt;
+ targetImage->setImageLayout(gpu,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
+ false);
+
+ srcTex->setImageLayout(gpu,
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ VK_ACCESS_SHADER_READ_BIT,
+ VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
+ false);
+
+ GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+ VK_ATTACHMENT_STORE_OP_STORE);
+ GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+ VK_ATTACHMENT_STORE_OP_STORE);
+ GrVkRenderPass::LoadStoreOps vkResolveOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+ VK_ATTACHMENT_STORE_OP_STORE);
+ const GrVkRenderPass* renderPass;
+ const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
+ rt->compatibleRenderPassHandle();
+ if (rpHandle.isValid()) {
+ renderPass = gpu->resourceProvider().findRenderPass(rpHandle,
+ vkColorOps,
+ vkResolveOps,
+ vkStencilOps);
+ } else {
+ renderPass = gpu->resourceProvider().findRenderPass(*rt,
+ vkColorOps,
+ vkResolveOps,
+ vkStencilOps);
+ }
+
+ SkASSERT(renderPass->isCompatible(*rt->simpleRenderPass()));
+
+
+ cmdBuffer->beginRenderPass(gpu, renderPass, 0, nullptr, *rt, bounds, false);
+ cmdBuffer->bindPipeline(gpu, pipeline);
+
+ // Uniform DescriptorSet, Sampler DescriptorSet, and vertex shader uniformBuffer
+ SkSTArray<3, const GrVkRecycledResource*> descriptorRecycledResources;
+ descriptorRecycledResources.push_back(uniformDS);
+ descriptorRecycledResources.push_back(samplerDS);
+ descriptorRecycledResources.push_back(fUniformBuffer->resource());
+
+ // One sampler, texture view, and texture
+ SkSTArray<3, const GrVkResource*> descriptorResources;
+ descriptorResources.push_back(sampler);
+ descriptorResources.push_back(srcTex->textureView(true));
+ descriptorResources.push_back(srcTex->resource());
+
+ cmdBuffer->bindDescriptorSets(gpu,
+ descriptorRecycledResources,
+ descriptorResources,
+ fPipelineLayout,
+ 0,
+ 2,
+ vkDescSets,
+ 0,
+ nullptr);
+
+ // Set Dynamic viewport and stencil
+ // We always use one viewport the size of the RT
+ VkViewport viewport;
+ viewport.x = 0.0f;
+ viewport.y = 0.0f;
+ viewport.width = SkIntToScalar(rt->width());
+ viewport.height = SkIntToScalar(rt->height());
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+ cmdBuffer->setViewport(gpu, 0, 1, &viewport);
+
+ // We assume the scissor is not enabled so just set it to the whole RT
+ VkRect2D scissor;
+ scissor.extent.width = rt->width();
+ scissor.extent.height = rt->height();
+ scissor.offset.x = 0;
+ scissor.offset.y = 0;
+ cmdBuffer->setScissor(gpu, 0, 1, &scissor);
+
+ cmdBuffer->bindVertexBuffer(gpu, fVertexBuffer);
+ cmdBuffer->draw(gpu, 4, 1, 0, 0);
+ cmdBuffer->endRenderPass(gpu);
+
+ // Release all temp resources which should now be reffed by the cmd buffer
+ pipeline->unref(gpu);
+ uniformDS->unref(gpu);
+ samplerDS->unref(gpu);
+ sampler->unref(gpu);
+ renderPass->unref(gpu);
+
+ return true;
+}
+
+void GrVkCopyManager::destroyResources(GrVkGpu* gpu) {
+ if (VK_NULL_HANDLE != fVertShaderModule) {
+ GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fVertShaderModule,
+ nullptr));
+ fVertShaderModule = VK_NULL_HANDLE;
+ }
+
+ if (VK_NULL_HANDLE != fFragShaderModule) {
+ GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fFragShaderModule,
+ nullptr));
+ fFragShaderModule = VK_NULL_HANDLE;
+ }
+
+ if (VK_NULL_HANDLE != fPipelineLayout) {
+ GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(), fPipelineLayout,
+ nullptr));
+ fPipelineLayout = VK_NULL_HANDLE;
+ }
+
+ if (fUniformBuffer) {
+ fUniformBuffer->release(gpu);
+ fUniformBuffer = nullptr;
+ }
+}
+
+void GrVkCopyManager::abandonResources() {
+ fVertShaderModule = VK_NULL_HANDLE;
+ fFragShaderModule = VK_NULL_HANDLE;
+ fPipelineLayout = VK_NULL_HANDLE;
+
+ if (fUniformBuffer) {
+ fUniformBuffer->abandon();
+ fUniformBuffer = nullptr;
+ }
+}
diff --git a/src/gpu/vk/GrVkCopyManager.h b/src/gpu/vk/GrVkCopyManager.h
new file mode 100644
index 0000000000..e19a14402d
--- /dev/null
+++ b/src/gpu/vk/GrVkCopyManager.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+*/
+
+#ifndef GrVkCopyManager_DEFINED
+#define GrVkCopyManager_DEFINED
+
+#include "GrVkDescriptorSetManager.h"
+
+#include "vk/GrVkDefines.h"
+
+class GrSurface;
+class GrVkCopyPipeline;
+class GrVkGpu;
+class GrVkUniformBuffer;
+class GrVkVertexBuffer;
+struct SkIPoint;
+struct SkIRect;
+
+class GrVkCopyManager {
+public:
+ GrVkCopyManager()
+ : fVertShaderModule(VK_NULL_HANDLE)
+ , fFragShaderModule(VK_NULL_HANDLE)
+ , fPipelineLayout(VK_NULL_HANDLE)
+ , fUniformBuffer(nullptr) {}
+
+ bool copySurfaceAsDraw(GrVkGpu* gpu,
+ GrSurface* dst,
+ GrSurface* src,
+ const SkIRect& srcRect,
+ const SkIPoint& dstPoint);
+
+ void destroyResources(GrVkGpu* gpu);
+ void abandonResources();
+
+private:
+ bool createCopyProgram(GrVkGpu* gpu);
+
+ // Everything below is only created once and shared by all copy draws/pipelines
+ VkShaderModule fVertShaderModule;
+ VkShaderModule fFragShaderModule;
+ VkPipelineShaderStageCreateInfo fShaderStageInfo[2];
+
+ GrVkDescriptorSetManager::Handle fSamplerDSHandle;
+ VkPipelineLayout fPipelineLayout;
+
+ SkAutoTUnref<GrVkVertexBuffer> fVertexBuffer;
+ GrVkUniformBuffer* fUniformBuffer;
+};
+
+#endif
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 6823bbc109..a72b517340 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -187,6 +187,8 @@ GrVkGpu::~GrVkGpu() {
}
#endif
+ fCopyManager.destroyResources(this);
+
// must call this just before we destroy the VkDevice
fResourceProvider.destroyResources();
@@ -1575,6 +1577,10 @@ bool GrVkGpu::onCopySurface(GrSurface* dst,
return true;
}
+ if (fCopyManager.copySurfaceAsDraw(this, dst, src, srcRect, dstPoint)) {
+ return true;
+ }
+
GrVkImage* dstImage;
GrVkImage* srcImage;
GrRenderTarget* dstRT = dst->asRenderTarget();
@@ -1604,11 +1610,6 @@ bool GrVkGpu::onCopySurface(GrSurface* dst,
return true;
}
- if (can_copy_as_draw(dst, src, this)) {
- this->copySurfaceAsDraw(dst, src, srcRect, dstPoint);
- return true;
- }
-
return false;
}
@@ -1618,7 +1619,14 @@ bool GrVkGpu::initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc)
// render target as well.
desc->fOrigin = src->origin();
desc->fConfig = src->config();
- desc->fFlags = src->numColorSamples() > 1 ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
+ if (src->numColorSamples() > 1 ||
+ (src->asTexture() && this->vkCaps().supportsCopiesAsDraws())) {
+ desc->fFlags = kRenderTarget_GrSurfaceFlag;
+ } else {
+ // Just going to use CopyImage here
+ desc->fFlags = kNone_GrSurfaceFlags;
+ }
+
return true;
}
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 8df6e6cfdc..eeaacf3d1b 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -14,6 +14,7 @@
#include "GrGpuFactory.h"
#include "vk/GrVkBackendContext.h"
#include "GrVkCaps.h"
+#include "GrVkCopyManager.h"
#include "GrVkIndexBuffer.h"
#include "GrVkMemory.h"
#include "GrVkResourceProvider.h"
@@ -59,7 +60,9 @@ public:
return fPhysDevMemProps;
}
- GrVkResourceProvider& resourceProvider() { return fResourceProvider; }
+ GrVkResourceProvider& resourceProvider() { return fResourceProvider; }
+
+ GrVkPrimaryCommandBuffer* currentCommandBuffer() { return fCurrentCmdBuffer; }
enum SyncQueue {
kForce_SyncQueue,
@@ -262,6 +265,8 @@ private:
SkAutoTDelete<GrVkHeap> fHeaps[kHeapCount];
+ GrVkCopyManager fCopyManager;
+
#ifdef SK_ENABLE_VK_LAYERS
// For reporting validation layer errors
VkDebugReportCallbackEXT fCallback;
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
index 419e1b9f2c..3ae54251b6 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
@@ -118,10 +118,12 @@ void GrVkGpuCommandBuffer::onSubmit(const SkIRect& bounds) {
// we don't attach the resolve to the framebuffer so no need to change its layout.
GrVkImage* targetImage = fRenderTarget->msaaImage() ? fRenderTarget->msaaImage()
: fRenderTarget;
+
+ // Change layout of our render target so it can be used as the color attachment
targetImage->setImageLayout(fGpu,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
false);
// If we are using a stencil attachment we also need to update its layout
@@ -131,7 +133,7 @@ void GrVkGpuCommandBuffer::onSubmit(const SkIRect& bounds) {
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
false);
}
diff --git a/src/gpu/vk/GrVkMemory.cpp b/src/gpu/vk/GrVkMemory.cpp
index f517b983aa..2853c89fee 100644
--- a/src/gpu/vk/GrVkMemory.cpp
+++ b/src/gpu/vk/GrVkMemory.cpp
@@ -242,7 +242,7 @@ VkPipelineStageFlags GrVkMemory::LayoutToPipelineStageFlags(const VkImageLayout
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout ||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+ return VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
} else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
return VK_PIPELINE_STAGE_HOST_BIT;
}
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
index 9a166ab3c1..69ae4a4989 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
@@ -58,7 +58,6 @@ void GrVkPipelineStateBuilder::finalizeFragmentSecondaryColor(GrGLSLShaderVar& o
outputColor.setLayoutQualifier("location = 0, index = 1");
}
-
bool GrVkPipelineStateBuilder::CreateVkShaderModule(const GrVkGpu* gpu,
VkShaderStageFlagBits stage,
const GrGLSLShaderBuilder& builder,
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index 8ae5162c5f..a7f07b0230 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -9,6 +9,7 @@
#include "GrTextureParams.h"
#include "GrVkCommandBuffer.h"
+#include "GrVkCopyPipeline.h"
#include "GrVkGLSLSampler.h"
#include "GrVkPipeline.h"
#include "GrVkRenderTarget.h"
@@ -67,6 +68,29 @@ GrVkPipeline* GrVkResourceProvider::createPipeline(const GrPipeline& pipeline,
primitiveType, renderPass, layout, fPipelineCache);
}
+GrVkCopyPipeline* GrVkResourceProvider::findOrCreateCopyPipeline(
+ const GrVkRenderTarget* dst,
+ VkPipelineShaderStageCreateInfo* shaderStageInfo,
+ VkPipelineLayout pipelineLayout) {
+ // Find or Create a compatible pipeline
+ GrVkCopyPipeline* pipeline = nullptr;
+ for (int i = 0; i < fCopyPipelines.count() && !pipeline; ++i) {
+ if (fCopyPipelines[i]->isCompatible(*dst->simpleRenderPass())) {
+ pipeline = fCopyPipelines[i];
+ }
+ }
+ if (!pipeline) {
+ pipeline = GrVkCopyPipeline::Create(fGpu, shaderStageInfo,
+ pipelineLayout,
+ dst->numColorSamples(),
+ *dst->simpleRenderPass(),
+ fPipelineCache);
+ fCopyPipelines.push_back(pipeline);
+ }
+ SkASSERT(pipeline);
+ pipeline->ref();
+ return pipeline;
+}
// To create framebuffers, we first need to create a simple RenderPass that is
// only used for framebuffer creation. When we actually render we will create
@@ -307,6 +331,11 @@ void GrVkResourceProvider::destroyResources() {
}
fAvailableSecondaryCommandBuffers.reset();
+ // Release all copy pipelines
+ for (int i = 0; i < fCopyPipelines.count(); ++i) {
+ fCopyPipelines[i]->unref(fGpu);
+ }
+
// loop over all render pass sets to make sure we destroy all the internal VkRenderPasses
for (int i = 0; i < fRenderPassArray.count(); ++i) {
fRenderPassArray[i].releaseResources(fGpu);
@@ -363,6 +392,11 @@ void GrVkResourceProvider::abandonResources() {
}
fAvailableSecondaryCommandBuffers.reset();
+ // Abandon all copy pipelines
+ for (int i = 0; i < fCopyPipelines.count(); ++i) {
+ fCopyPipelines[i]->unrefAndAbandon();
+ }
+
// loop over all render pass sets to make sure we destroy all the internal VkRenderPasses
for (int i = 0; i < fRenderPassArray.count(); ++i) {
fRenderPassArray[i].abandonResources();
diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h
index 19d493af92..b9e98e72cc 100644
--- a/src/gpu/vk/GrVkResourceProvider.h
+++ b/src/gpu/vk/GrVkResourceProvider.h
@@ -26,6 +26,7 @@
class GrPipeline;
class GrPrimitiveProcessor;
class GrTextureParams;
+class GrVkCopyPipeline;
class GrVkGpu;
class GrVkPipeline;
class GrVkPrimaryCommandBuffer;
@@ -50,6 +51,10 @@ public:
const GrVkRenderPass& renderPass,
VkPipelineLayout layout);
+ GrVkCopyPipeline* findOrCreateCopyPipeline(const GrVkRenderTarget* dst,
+ VkPipelineShaderStageCreateInfo*,
+ VkPipelineLayout);
+
GR_DEFINE_RESOURCE_HANDLE_CLASS(CompatibleRPHandle);
// Finds or creates a simple render pass that matches the target, increments the refcount,
@@ -224,6 +229,9 @@ private:
// Central cache for creating pipelines
VkPipelineCache fPipelineCache;
+ // Cache of previously created copy pipelines
+ SkTArray<GrVkCopyPipeline*> fCopyPipelines;
+
SkSTArray<4, CompatibleRenderPassSet> fRenderPassArray;
// Array of PrimaryCommandBuffers that are currently in flight
diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp
index 0d07e1f57a..a14f827dcb 100644
--- a/src/gpu/vk/GrVkUtil.cpp
+++ b/src/gpu/vk/GrVkUtil.cpp
@@ -312,7 +312,7 @@ bool GrCompileVkShaderModule(const GrVkGpu* gpu,
shaderc_shader_kind shadercStage = vk_shader_stage_to_shaderc_kind(stage);
result = shaderc_compile_into_spv(compiler,
- shaderString.c_str(),
+ shaderString,
strlen(shaderString),
shadercStage,
"shader",