• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GrVkMSAALoadManager()24 GrVkMSAALoadManager::GrVkMSAALoadManager()
25         : fVertShaderModule(VK_NULL_HANDLE)
26         , fFragShaderModule(VK_NULL_HANDLE)
27         , fPipelineLayout(VK_NULL_HANDLE) {}
28 
~GrVkMSAALoadManager()29 GrVkMSAALoadManager::~GrVkMSAALoadManager() {}
30 
createMSAALoadProgram(GrVkGpu * gpu)31 bool 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 
loadMSAAFromResolve(GrVkGpu * gpu,GrVkCommandBuffer * commandBuffer,const GrVkRenderPass & renderPass,GrAttachment * dst,GrVkImage * src,const SkIRect & rect)116 bool 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 
destroyResources(GrVkGpu * gpu)217 void 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