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