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