Greg Daniel | a8c3210 | 2020-12-30 15:09:32 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2020 Google LLC |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #include "src/gpu/vk/GrVkMSAALoadManager.h" |
| 9 | |
| 10 | #include "src/core/SkTraceEvent.h" |
| 11 | #include "src/gpu/vk/GrVkCommandBuffer.h" |
| 12 | #include "src/gpu/vk/GrVkDescriptorSet.h" |
| 13 | #include "src/gpu/vk/GrVkGpu.h" |
| 14 | #include "src/gpu/vk/GrVkImageView.h" |
| 15 | #include "src/gpu/vk/GrVkMeshBuffer.h" |
| 16 | #include "src/gpu/vk/GrVkPipeline.h" |
| 17 | #include "src/gpu/vk/GrVkRenderTarget.h" |
| 18 | #include "src/gpu/vk/GrVkResourceProvider.h" |
| 19 | #include "src/gpu/vk/GrVkUniformBuffer.h" |
| 20 | #include "src/gpu/vk/GrVkUtil.h" |
| 21 | |
| 22 | GrVkMSAALoadManager::GrVkMSAALoadManager() |
| 23 | : fVertShaderModule(VK_NULL_HANDLE) |
| 24 | , fFragShaderModule(VK_NULL_HANDLE) |
| 25 | , fPipelineLayout(VK_NULL_HANDLE) {} |
| 26 | |
| 27 | GrVkMSAALoadManager::~GrVkMSAALoadManager() {} |
| 28 | |
| 29 | bool GrVkMSAALoadManager::createMSAALoadProgram(GrVkGpu* gpu) { |
| 30 | TRACE_EVENT0("skia", TRACE_FUNC); |
| 31 | |
| 32 | SkSL::String vertShaderText; |
| 33 | vertShaderText.append( |
| 34 | "#extension GL_ARB_separate_shader_objects : enable\n" |
| 35 | "#extension GL_ARB_shading_language_420pack : enable\n" |
| 36 | |
| 37 | "layout(set = 0, binding = 0) uniform vertexUniformBuffer {" |
| 38 | "half4 uPosXform;" |
| 39 | "};" |
| 40 | |
| 41 | "// MSAA Load Program VS\n" |
| 42 | "void main() {" |
| 43 | "float2 position = float2(sk_VertexID >> 1, sk_VertexID & 1);" |
| 44 | "sk_Position.xy = position * uPosXform.xy + uPosXform.zw;" |
| 45 | "sk_Position.zw = half2(0, 1);" |
| 46 | "}"); |
| 47 | |
| 48 | SkSL::String fragShaderText; |
| 49 | fragShaderText.append( |
| 50 | "#extension GL_ARB_separate_shader_objects : enable\n" |
| 51 | "#extension GL_ARB_shading_language_420pack : enable\n" |
| 52 | |
| 53 | "layout(input_attachment_index = 0, set = 2, binding = 0) uniform subpassInput uInput;" |
| 54 | |
| 55 | "// MSAA Load Program FS\n" |
| 56 | "void main() {" |
| 57 | "sk_FragColor = subpassLoad(uInput);" |
| 58 | "}"); |
| 59 | |
| 60 | SkSL::Program::Settings settings; |
| 61 | SkSL::String spirv; |
| 62 | SkSL::Program::Inputs inputs; |
| 63 | if (!GrCompileVkShaderModule(gpu, vertShaderText, VK_SHADER_STAGE_VERTEX_BIT, |
| 64 | &fVertShaderModule, &fShaderStageInfo[0], settings, &spirv, |
| 65 | &inputs)) { |
| 66 | this->destroyResources(gpu); |
| 67 | return false; |
| 68 | } |
| 69 | SkASSERT(inputs.isEmpty()); |
| 70 | |
| 71 | if (!GrCompileVkShaderModule(gpu, fragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, |
| 72 | &fFragShaderModule, &fShaderStageInfo[1], settings, &spirv, |
| 73 | &inputs)) { |
| 74 | this->destroyResources(gpu); |
| 75 | return false; |
| 76 | } |
| 77 | SkASSERT(inputs.isEmpty()); |
| 78 | |
| 79 | VkDescriptorSetLayout dsLayout[GrVkUniformHandler::kDescSetCount]; |
| 80 | |
| 81 | GrVkResourceProvider& resourceProvider = gpu->resourceProvider(); |
| 82 | |
| 83 | dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout(); |
| 84 | |
| 85 | // Even though we don't have a sampler we need to put a valid handle here (of zero samplers) |
| 86 | // since we set up our descriptor layout to be uniform, sampler, input. |
| 87 | // |
| 88 | // TODO: We should have a more general way for different pipelines to describe their descriptor |
| 89 | // layouts so that we don't have to use the compile time constants for the sets. |
| 90 | GrVkDescriptorSetManager::Handle samplerHandle; |
| 91 | resourceProvider.getZeroSamplerDescriptorSetHandle(&samplerHandle); |
| 92 | |
| 93 | dsLayout[GrVkUniformHandler::kSamplerDescSet] = |
| 94 | resourceProvider.getSamplerDSLayout(samplerHandle); |
| 95 | |
| 96 | dsLayout[GrVkUniformHandler::kInputDescSet] = resourceProvider.getInputDSLayout(); |
| 97 | |
| 98 | // Create the VkPipelineLayout |
| 99 | VkPipelineLayoutCreateInfo layoutCreateInfo; |
| 100 | memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags)); |
| 101 | layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; |
| 102 | layoutCreateInfo.pNext = nullptr; |
| 103 | layoutCreateInfo.flags = 0; |
| 104 | layoutCreateInfo.setLayoutCount = GrVkUniformHandler::kDescSetCount; |
| 105 | layoutCreateInfo.pSetLayouts = dsLayout; |
| 106 | layoutCreateInfo.pushConstantRangeCount = 0; |
| 107 | layoutCreateInfo.pPushConstantRanges = nullptr; |
| 108 | |
| 109 | VkResult err = GR_VK_CALL( |
| 110 | gpu->vkInterface(), |
| 111 | CreatePipelineLayout(gpu->device(), &layoutCreateInfo, nullptr, &fPipelineLayout)); |
| 112 | if (err) { |
| 113 | this->destroyResources(gpu); |
| 114 | return false; |
| 115 | } |
| 116 | |
| 117 | // We use 1 half4's for uniforms |
| 118 | fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, 4 * sizeof(float))); |
| 119 | SkASSERT(fUniformBuffer.get()); |
| 120 | |
| 121 | return true; |
| 122 | } |
| 123 | |
| 124 | bool GrVkMSAALoadManager::loadMSAAFromResolve(GrVkGpu* gpu, |
| 125 | GrVkCommandBuffer* commandBuffer, |
| 126 | const GrVkRenderPass& renderPass, |
| 127 | GrSurface* dst, |
| 128 | GrSurface* src, |
| 129 | const SkIRect& rect) { |
| 130 | GrVkRenderTarget* dstRt = static_cast<GrVkRenderTarget*>(dst->asRenderTarget()); |
| 131 | if (!dstRt) { |
| 132 | return false; |
| 133 | } |
| 134 | |
| 135 | GrVkRenderTarget* srcRT = static_cast<GrVkRenderTarget*>(src->asRenderTarget()); |
| 136 | if (!srcRT) { |
| 137 | return false; |
| 138 | } |
| 139 | |
| 140 | if (!srcRT->supportsInputAttachmentUsage()) { |
| 141 | return false; |
| 142 | } |
| 143 | |
| 144 | if (VK_NULL_HANDLE == fVertShaderModule) { |
Greg Daniel | b8aa5f2 | 2020-12-30 16:57:32 -0500 | [diff] [blame^] | 145 | SkASSERT(fFragShaderModule == VK_NULL_HANDLE && fPipelineLayout == VK_NULL_HANDLE && |
Greg Daniel | a8c3210 | 2020-12-30 15:09:32 -0500 | [diff] [blame] | 146 | fUniformBuffer.get() == nullptr); |
| 147 | if (!this->createMSAALoadProgram(gpu)) { |
| 148 | SkDebugf("Failed to create copy program.\n"); |
| 149 | return false; |
| 150 | } |
| 151 | } |
Greg Daniel | b8aa5f2 | 2020-12-30 16:57:32 -0500 | [diff] [blame^] | 152 | SkASSERT(fPipelineLayout != VK_NULL_HANDLE); |
Greg Daniel | a8c3210 | 2020-12-30 15:09:32 -0500 | [diff] [blame] | 153 | |
| 154 | GrVkResourceProvider& resourceProv = gpu->resourceProvider(); |
| 155 | |
| 156 | const GrVkPipeline* pipeline = |
| 157 | resourceProv.findOrCreateMSAALoadPipeline(renderPass, dstRt, fShaderStageInfo, |
| 158 | fPipelineLayout); |
| 159 | if (!pipeline) { |
| 160 | return false; |
| 161 | } |
| 162 | commandBuffer->bindPipeline(gpu, pipeline); |
| 163 | // Release ref to pipeline. The command buffer is holding a ref. |
| 164 | pipeline->unref(); |
| 165 | |
| 166 | // Set Dynamic viewport and stencil |
| 167 | // We always use one viewport the size of the RT |
| 168 | VkViewport viewport; |
| 169 | viewport.x = 0.0f; |
| 170 | viewport.y = 0.0f; |
| 171 | viewport.width = SkIntToScalar(dst->width()); |
| 172 | viewport.height = SkIntToScalar(dst->height()); |
| 173 | viewport.minDepth = 0.0f; |
| 174 | viewport.maxDepth = 1.0f; |
| 175 | commandBuffer->setViewport(gpu, 0, 1, &viewport); |
| 176 | |
| 177 | // We assume the scissor is not enabled so just set it to the whole RT |
| 178 | VkRect2D scissor; |
| 179 | scissor.extent.width = dst->width(); |
| 180 | scissor.extent.height = dst->height(); |
| 181 | scissor.offset.x = 0; |
| 182 | scissor.offset.y = 0; |
| 183 | commandBuffer->setScissor(gpu, 0, 1, &scissor); |
| 184 | |
| 185 | // Update and bind uniform descriptor set |
| 186 | int w = rect.width(); |
| 187 | int h = rect.height(); |
| 188 | |
| 189 | // dst rect edges in NDC (-1 to 1) |
| 190 | int dw = dst->width(); |
| 191 | int dh = dst->height(); |
| 192 | float dx0 = 2.f * rect.fLeft / dw - 1.f; |
| 193 | float dx1 = 2.f * (rect.fLeft + w) / dw - 1.f; |
| 194 | float dy0 = 2.f * rect.fTop / dh - 1.f; |
| 195 | float dy1 = 2.f * (rect.fTop + h) / dh - 1.f; |
| 196 | |
| 197 | float uniData[] = {dx1 - dx0, dy1 - dy0, dx0, dy0}; // posXform |
| 198 | |
| 199 | fUniformBuffer->updateData(gpu, uniData, sizeof(uniData), nullptr); |
| 200 | static_assert(GrVkUniformHandler::kUniformBufferDescSet < GrVkUniformHandler::kInputDescSet); |
| 201 | commandBuffer->bindDescriptorSets(gpu, fPipelineLayout, |
| 202 | GrVkUniformHandler::kUniformBufferDescSet, |
| 203 | /*setCount=*/1, fUniformBuffer->descriptorSet(), |
| 204 | /*dynamicOffsetCount=*/0, /*dynamicOffsets=*/nullptr); |
| 205 | commandBuffer->addRecycledResource(fUniformBuffer->resource()); |
| 206 | |
| 207 | // Update the input descriptor set |
| 208 | const GrVkDescriptorSet* inputDS = srcRT->inputDescSet(gpu, /*forResolve=*/true); |
| 209 | if (!inputDS) { |
| 210 | return false; |
| 211 | } |
| 212 | commandBuffer->bindDescriptorSets(gpu, fPipelineLayout, |
| 213 | GrVkUniformHandler::kInputDescSet, /*setCount=*/1, |
| 214 | inputDS->descriptorSet(), |
| 215 | /*dynamicOffsetCount=*/0, /*dynamicOffsets=*/nullptr); |
| 216 | |
| 217 | // We don't need to add the src and dst resources here since those are all tracked by the main |
| 218 | // render pass code out in GrVkOpsRenderPass and GrVkRenderTarget::adResources. |
| 219 | commandBuffer->addRecycledResource(inputDS); |
| 220 | |
| 221 | commandBuffer->draw(gpu, 4, 1, 0, 0); |
| 222 | |
| 223 | return true; |
| 224 | } |
| 225 | |
| 226 | void GrVkMSAALoadManager::destroyResources(GrVkGpu* gpu) { |
| 227 | if (fVertShaderModule != VK_NULL_HANDLE) { |
| 228 | GR_VK_CALL(gpu->vkInterface(), |
| 229 | DestroyShaderModule(gpu->device(), fVertShaderModule, nullptr)); |
| 230 | fVertShaderModule = VK_NULL_HANDLE; |
| 231 | } |
| 232 | |
| 233 | if (fFragShaderModule != VK_NULL_HANDLE) { |
| 234 | GR_VK_CALL(gpu->vkInterface(), |
| 235 | DestroyShaderModule(gpu->device(), fFragShaderModule, nullptr)); |
| 236 | fFragShaderModule = VK_NULL_HANDLE; |
| 237 | } |
| 238 | |
| 239 | if (fPipelineLayout != VK_NULL_HANDLE) { |
| 240 | GR_VK_CALL(gpu->vkInterface(), |
| 241 | DestroyPipelineLayout(gpu->device(), fPipelineLayout, nullptr)); |
| 242 | fPipelineLayout = VK_NULL_HANDLE; |
| 243 | } |
| 244 | |
| 245 | if (fUniformBuffer) { |
| 246 | fUniformBuffer->release(gpu); |
| 247 | fUniformBuffer.reset(); |
| 248 | } |
| 249 | } |
| 250 | |