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