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