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