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