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