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