diff options
author | egdaniel <egdaniel@google.com> | 2016-09-27 08:00:53 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-09-27 08:00:53 -0700 |
commit | bc9b2963bf9e39c47ae5c3ab94b8503b476f4f0e (patch) | |
tree | dd1fe0200d6191882ffb251d1a150f32f418b3cd /src | |
parent | cefee07bf7c5f8ae3016d8c00674f078c2fdb592 (diff) |
Add GrVkCopyPipeline to handle vulkan copies as draws
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2274663005
Review-Url: https://codereview.chromium.org/2274663005
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/vk/GrVkCaps.cpp | 1 | ||||
-rw-r--r-- | src/gpu/vk/GrVkCaps.h | 7 | ||||
-rw-r--r-- | src/gpu/vk/GrVkCommandBuffer.cpp | 26 | ||||
-rw-r--r-- | src/gpu/vk/GrVkCommandBuffer.h | 10 | ||||
-rw-r--r-- | src/gpu/vk/GrVkCopyManager.cpp | 409 | ||||
-rw-r--r-- | src/gpu/vk/GrVkCopyManager.h | 55 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.cpp | 20 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.h | 7 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpuCommandBuffer.cpp | 6 | ||||
-rw-r--r-- | src/gpu/vk/GrVkMemory.cpp | 2 | ||||
-rw-r--r-- | src/gpu/vk/GrVkPipelineStateBuilder.cpp | 1 | ||||
-rw-r--r-- | src/gpu/vk/GrVkResourceProvider.cpp | 34 | ||||
-rw-r--r-- | src/gpu/vk/GrVkResourceProvider.h | 8 | ||||
-rw-r--r-- | src/gpu/vk/GrVkUtil.cpp | 2 |
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", |