1 /*
2  * Copyright 2016 Google Inc.
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 "GrVkCopyManager.h"
9 
10 #include "GrRenderTargetPriv.h"
11 #include "GrSamplerState.h"
12 #include "GrShaderCaps.h"
13 #include "GrSurface.h"
14 #include "GrTexturePriv.h"
15 #include "GrVkCommandBuffer.h"
16 #include "GrVkCommandPool.h"
17 #include "GrVkCopyPipeline.h"
18 #include "GrVkDescriptorSet.h"
19 #include "GrVkGpu.h"
20 #include "GrVkImageView.h"
21 #include "GrVkPipelineLayout.h"
22 #include "GrVkRenderTarget.h"
23 #include "GrVkResourceProvider.h"
24 #include "GrVkSampler.h"
25 #include "GrVkTexture.h"
26 #include "GrVkUniformBuffer.h"
27 #include "GrVkVertexBuffer.h"
28 #include "SkPoint.h"
29 #include "SkRect.h"
30 #include "SkTraceEvent.h"
31 
GrVkCopyManager()32 GrVkCopyManager::GrVkCopyManager()
33     : fVertShaderModule(VK_NULL_HANDLE)
34     , fFragShaderModule(VK_NULL_HANDLE)
35     , fPipelineLayout(nullptr) {}
36 
~GrVkCopyManager()37 GrVkCopyManager::~GrVkCopyManager() {}
38 
createCopyProgram(GrVkGpu * gpu)39 bool GrVkCopyManager::createCopyProgram(GrVkGpu* gpu) {
40     TRACE_EVENT0("skia", TRACE_FUNC);
41 
42     const GrShaderCaps* shaderCaps = gpu->caps()->shaderCaps();
43     const char* version = shaderCaps->versionDeclString();
44     SkString vertShaderText(version);
45     vertShaderText.append(
46         "#extension GL_ARB_separate_shader_objects : enable\n"
47         "#extension GL_ARB_shading_language_420pack : enable\n"
48 
49         "layout(set = 0, binding = 0) uniform vertexUniformBuffer {"
50             "half4 uPosXform;"
51             "half4 uTexCoordXform;"
52         "};"
53         "layout(location = 0) in float2 inPosition;"
54         "layout(location = 1) out half2 vTexCoord;"
55 
56         "// Copy Program VS\n"
57         "void main() {"
58             "vTexCoord = half2(inPosition * uTexCoordXform.xy + uTexCoordXform.zw);"
59             "sk_Position.xy = inPosition * uPosXform.xy + uPosXform.zw;"
60             "sk_Position.zw = half2(0, 1);"
61         "}"
62     );
63 
64     SkString fragShaderText(version);
65     fragShaderText.append(
66         "#extension GL_ARB_separate_shader_objects : enable\n"
67         "#extension GL_ARB_shading_language_420pack : enable\n"
68 
69         "layout(set = 1, binding = 0) uniform sampler2D uTextureSampler;"
70         "layout(location = 1) in half2 vTexCoord;"
71 
72         "// Copy Program FS\n"
73         "void main() {"
74             "sk_FragColor = texture(uTextureSampler, vTexCoord);"
75         "}"
76     );
77 
78     SkSL::Program::Settings settings;
79     SkSL::String spirv;
80     SkSL::Program::Inputs inputs;
81     if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(), VK_SHADER_STAGE_VERTEX_BIT,
82                                  &fVertShaderModule, &fShaderStageInfo[0], settings, &spirv,
83                                  &inputs)) {
84         this->destroyResources(gpu);
85         return false;
86     }
87     SkASSERT(inputs.isEmpty());
88 
89     if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT,
90                                  &fFragShaderModule, &fShaderStageInfo[1], settings, &spirv,
91                                  &inputs)) {
92         this->destroyResources(gpu);
93         return false;
94     }
95     SkASSERT(inputs.isEmpty());
96 
97     VkDescriptorSetLayout dsLayout[2];
98 
99     GrVkResourceProvider& resourceProvider = gpu->resourceProvider();
100 
101     dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout();
102 
103     uint32_t samplerVisibility = kFragment_GrShaderFlag;
104     SkTArray<uint32_t> visibilityArray(&samplerVisibility, 1);
105 
106     resourceProvider.getSamplerDescriptorSetHandle(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
107                                                    visibilityArray, &fSamplerDSHandle);
108     dsLayout[GrVkUniformHandler::kSamplerDescSet] =
109         resourceProvider.getSamplerDSLayout(fSamplerDSHandle);
110 
111     // Create the VkPipelineLayout
112     VkPipelineLayoutCreateInfo layoutCreateInfo;
113     memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags));
114     layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
115     layoutCreateInfo.pNext = 0;
116     layoutCreateInfo.flags = 0;
117     layoutCreateInfo.setLayoutCount = 2;
118     layoutCreateInfo.pSetLayouts = dsLayout;
119     layoutCreateInfo.pushConstantRangeCount = 0;
120     layoutCreateInfo.pPushConstantRanges = nullptr;
121 
122     VkPipelineLayout pipelineLayout;
123     VkResult err = GR_VK_CALL(gpu->vkInterface(), CreatePipelineLayout(gpu->device(),
124                                                                        &layoutCreateInfo,
125                                                                        nullptr,
126                                                                        &pipelineLayout));
127     if (err) {
128         this->destroyResources(gpu);
129         return false;
130     }
131 
132     fPipelineLayout = new GrVkPipelineLayout(pipelineLayout);
133 
134     static const float vdata[] = {
135         0, 0,
136         0, 1,
137         1, 0,
138         1, 1
139     };
140     fVertexBuffer = GrVkVertexBuffer::Make(gpu, sizeof(vdata), false);
141     SkASSERT(fVertexBuffer.get());
142     fVertexBuffer->updateData(vdata, sizeof(vdata));
143 
144     // We use 2 float4's for uniforms
145     fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, 8 * sizeof(float)));
146     SkASSERT(fUniformBuffer.get());
147 
148     return true;
149 }
150 
copySurfaceAsDraw(GrVkGpu * gpu,GrSurface * dst,GrSurfaceOrigin dstOrigin,GrSurface * src,GrSurfaceOrigin srcOrigin,const SkIRect & srcRect,const SkIPoint & dstPoint,bool canDiscardOutsideDstRect)151 bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu,
152                                         GrSurface* dst, GrSurfaceOrigin dstOrigin,
153                                         GrSurface* src, GrSurfaceOrigin srcOrigin,
154                                         const SkIRect& srcRect, const SkIPoint& dstPoint,
155                                         bool canDiscardOutsideDstRect) {
156     // None of our copy methods can handle a swizzle. TODO: Make copySurfaceAsDraw handle the
157     // swizzle.
158     if (gpu->caps()->shaderCaps()->configOutputSwizzle(src->config()) !=
159         gpu->caps()->shaderCaps()->configOutputSwizzle(dst->config())) {
160         return false;
161     }
162 
163     GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(dst->asRenderTarget());
164     if (!rt) {
165         return false;
166     }
167 
168     GrVkTexture* srcTex = static_cast<GrVkTexture*>(src->asTexture());
169     if (!srcTex) {
170         return false;
171     }
172 
173     if (VK_NULL_HANDLE == fVertShaderModule) {
174         SkASSERT(VK_NULL_HANDLE == fFragShaderModule &&
175                  nullptr == fPipelineLayout &&
176                  nullptr == fVertexBuffer.get() &&
177                  nullptr == fUniformBuffer.get());
178         if (!this->createCopyProgram(gpu)) {
179             SkDebugf("Failed to create copy program.\n");
180             return false;
181         }
182     }
183     SkASSERT(fPipelineLayout);
184 
185     GrVkResourceProvider& resourceProv = gpu->resourceProvider();
186 
187     GrVkCopyPipeline* pipeline = resourceProv.findOrCreateCopyPipeline(rt,
188                                                                        fShaderStageInfo,
189                                                                        fPipelineLayout->layout());
190     if (!pipeline) {
191         return false;
192     }
193 
194     // UPDATE UNIFORM DESCRIPTOR SET
195     int w = srcRect.width();
196     int h = srcRect.height();
197 
198     // dst rect edges in NDC (-1 to 1)
199     int dw = dst->width();
200     int dh = dst->height();
201     float dx0 = 2.f * dstPoint.fX / dw - 1.f;
202     float dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f;
203     float dy0 = 2.f * dstPoint.fY / dh - 1.f;
204     float dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f;
205     if (kBottomLeft_GrSurfaceOrigin == dstOrigin) {
206         dy0 = -dy0;
207         dy1 = -dy1;
208     }
209 
210 
211     float sx0 = (float)srcRect.fLeft;
212     float sx1 = (float)(srcRect.fLeft + w);
213     float sy0 = (float)srcRect.fTop;
214     float sy1 = (float)(srcRect.fTop + h);
215     int sh = src->height();
216     if (kBottomLeft_GrSurfaceOrigin == srcOrigin) {
217         sy0 = sh - sy0;
218         sy1 = sh - sy1;
219     }
220     // src rect edges in normalized texture space (0 to 1).
221     int sw = src->width();
222     sx0 /= sw;
223     sx1 /= sw;
224     sy0 /= sh;
225     sy1 /= sh;
226 
227     float uniData[] = { dx1 - dx0, dy1 - dy0, dx0, dy0,    // posXform
228                         sx1 - sx0, sy1 - sy0, sx0, sy0 };  // texCoordXform
229 
230     fUniformBuffer->updateData(gpu, uniData, sizeof(uniData), nullptr);
231 
232     const GrVkDescriptorSet* uniformDS = resourceProv.getUniformDescriptorSet();
233     SkASSERT(uniformDS);
234 
235     VkDescriptorBufferInfo uniBufferInfo;
236     uniBufferInfo.buffer = fUniformBuffer->buffer();
237     uniBufferInfo.offset = fUniformBuffer->offset();
238     uniBufferInfo.range = fUniformBuffer->size();
239 
240     VkWriteDescriptorSet descriptorWrites;
241     descriptorWrites.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
242     descriptorWrites.pNext = nullptr;
243     descriptorWrites.dstSet = uniformDS->descriptorSet();
244     descriptorWrites.dstBinding = GrVkUniformHandler::kGeometryBinding;
245     descriptorWrites.dstArrayElement = 0;
246     descriptorWrites.descriptorCount = 1;
247     descriptorWrites.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
248     descriptorWrites.pImageInfo = nullptr;
249     descriptorWrites.pBufferInfo = &uniBufferInfo;
250     descriptorWrites.pTexelBufferView = nullptr;
251 
252     GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
253                                                         1,
254                                                         &descriptorWrites,
255                                                         0, nullptr));
256 
257     // UPDATE SAMPLER DESCRIPTOR SET
258     const GrVkDescriptorSet* samplerDS =
259         gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle);
260 
261     GrSamplerState samplerState = GrSamplerState::ClampNearest();
262 
263     GrVkSampler* sampler = resourceProv.findOrCreateCompatibleSampler(
264             samplerState, GrVkYcbcrConversionInfo());
265 
266     VkDescriptorImageInfo imageInfo;
267     memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
268     imageInfo.sampler = sampler->sampler();
269     imageInfo.imageView = srcTex->textureView()->imageView();
270     imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
271 
272     VkWriteDescriptorSet writeInfo;
273     memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet));
274     writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
275     writeInfo.pNext = nullptr;
276     writeInfo.dstSet = samplerDS->descriptorSet();
277     writeInfo.dstBinding = 0;
278     writeInfo.dstArrayElement = 0;
279     writeInfo.descriptorCount = 1;
280     writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
281     writeInfo.pImageInfo = &imageInfo;
282     writeInfo.pBufferInfo = nullptr;
283     writeInfo.pTexelBufferView = nullptr;
284 
285     GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
286                                                         1,
287                                                         &writeInfo,
288                                                         0, nullptr));
289 
290     VkDescriptorSet vkDescSets[] = { uniformDS->descriptorSet(), samplerDS->descriptorSet() };
291 
292     GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(srcTex->asRenderTarget());
293     if (texRT) {
294         gpu->resolveRenderTargetNoFlush(texRT);
295     }
296 
297     // TODO: Make tighter bounds and then adjust bounds for origin and granularity if we see
298     //       any perf issues with using the whole bounds
299     SkIRect bounds = SkIRect::MakeWH(rt->width(), rt->height());
300 
301     // Change layouts of rt and texture. We aren't blending so we don't need color attachment read
302     // access for blending.
303     GrVkImage* targetImage = rt->msaaImage() ? rt->msaaImage() : rt;
304     VkAccessFlags dstAccessFlags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
305     if (!canDiscardOutsideDstRect) {
306         // We need to load the color attachment so need to be able to read it.
307         dstAccessFlags |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
308     }
309     targetImage->setImageLayout(gpu,
310                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
311                                 dstAccessFlags,
312                                 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
313                                 false);
314 
315     srcTex->setImageLayout(gpu,
316                            VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
317                            VK_ACCESS_SHADER_READ_BIT,
318                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
319                            false);
320 
321     GrStencilAttachment* stencil = rt->renderTargetPriv().getStencilAttachment();
322     if (stencil) {
323         GrVkStencilAttachment* vkStencil = (GrVkStencilAttachment*)stencil;
324         // We aren't actually using the stencil but we still load and store it so we need
325         // appropriate barriers.
326         // TODO: Once we refactor surface and how we conntect stencil to RTs, we should not even
327         // have the stencil on this render pass if possible.
328         vkStencil->setImageLayout(gpu,
329                                   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
330                                   VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
331                                   VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
332                                   VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
333                                   false);
334     }
335 
336     VkAttachmentLoadOp loadOp = canDiscardOutsideDstRect ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
337                                                          : VK_ATTACHMENT_LOAD_OP_LOAD;
338     GrVkRenderPass::LoadStoreOps vkColorOps(loadOp, VK_ATTACHMENT_STORE_OP_STORE);
339     GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD,
340                                               VK_ATTACHMENT_STORE_OP_STORE);
341     const GrVkRenderPass* renderPass;
342     const GrVkResourceProvider::CompatibleRPHandle& rpHandle = rt->compatibleRenderPassHandle();
343     if (rpHandle.isValid()) {
344         renderPass = gpu->resourceProvider().findRenderPass(rpHandle,
345                                                             vkColorOps,
346                                                             vkStencilOps);
347     } else {
348         renderPass = gpu->resourceProvider().findRenderPass(*rt,
349                                                             vkColorOps,
350                                                             vkStencilOps);
351     }
352 
353     SkASSERT(renderPass->isCompatible(*rt->simpleRenderPass()));
354 
355     GrVkPrimaryCommandBuffer* cmdBuffer = gpu->currentCommandBuffer();
356     cmdBuffer->beginRenderPass(gpu, renderPass, nullptr, *rt, bounds, true);
357 
358     GrVkSecondaryCommandBuffer* secondary = gpu->cmdPool()->findOrCreateSecondaryCommandBuffer(gpu);
359     if (!secondary) {
360         return false;
361     }
362     secondary->begin(gpu, rt->framebuffer(), renderPass);
363 
364     secondary->bindPipeline(gpu, pipeline);
365 
366     // Uniform DescriptorSet, Sampler DescriptorSet, and vertex shader uniformBuffer
367     SkSTArray<3, const GrVkRecycledResource*> descriptorRecycledResources;
368     descriptorRecycledResources.push_back(uniformDS);
369     descriptorRecycledResources.push_back(samplerDS);
370     descriptorRecycledResources.push_back(fUniformBuffer->resource());
371 
372     // One sampler, texture view, and texture
373     SkSTArray<3, const GrVkResource*> descriptorResources;
374     descriptorResources.push_back(sampler);
375     descriptorResources.push_back(srcTex->textureView());
376     descriptorResources.push_back(srcTex->resource());
377 
378     secondary->bindDescriptorSets(gpu,
379                                   descriptorRecycledResources,
380                                   descriptorResources,
381                                   fPipelineLayout,
382                                   0,
383                                   2,
384                                   vkDescSets,
385                                   0,
386                                   nullptr);
387 
388     // Set Dynamic viewport and stencil
389     // We always use one viewport the size of the RT
390     VkViewport viewport;
391     viewport.x = 0.0f;
392     viewport.y = 0.0f;
393     viewport.width = SkIntToScalar(rt->width());
394     viewport.height = SkIntToScalar(rt->height());
395     viewport.minDepth = 0.0f;
396     viewport.maxDepth = 1.0f;
397     secondary->setViewport(gpu, 0, 1, &viewport);
398 
399     // We assume the scissor is not enabled so just set it to the whole RT
400     VkRect2D scissor;
401     scissor.extent.width = rt->width();
402     scissor.extent.height = rt->height();
403     scissor.offset.x = 0;
404     scissor.offset.y = 0;
405     secondary->setScissor(gpu, 0, 1, &scissor);
406 
407     secondary->bindInputBuffer(gpu, 0, fVertexBuffer.get());
408     secondary->draw(gpu, 4, 1, 0, 0);
409     secondary->end(gpu);
410     cmdBuffer->executeCommands(gpu, secondary);
411     cmdBuffer->endRenderPass(gpu);
412     secondary->unref(gpu);
413 
414     // Release all temp resources which should now be reffed by the cmd buffer
415     pipeline->unref(gpu);
416     uniformDS->unref(gpu);
417     samplerDS->unref(gpu);
418     sampler->unref(gpu);
419     renderPass->unref(gpu);
420 
421     return true;
422 }
423 
destroyResources(GrVkGpu * gpu)424 void GrVkCopyManager::destroyResources(GrVkGpu* gpu) {
425     if (VK_NULL_HANDLE != fVertShaderModule) {
426         GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fVertShaderModule,
427                                                            nullptr));
428         fVertShaderModule = VK_NULL_HANDLE;
429     }
430 
431     if (VK_NULL_HANDLE != fFragShaderModule) {
432         GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fFragShaderModule,
433                                                            nullptr));
434         fFragShaderModule = VK_NULL_HANDLE;
435     }
436 
437     if (fPipelineLayout) {
438         fPipelineLayout->unref(gpu);
439         fPipelineLayout = nullptr;
440     }
441 
442     if (fUniformBuffer) {
443         fUniformBuffer->release(gpu);
444         fUniformBuffer.reset();
445     }
446 }
447 
abandonResources()448 void GrVkCopyManager::abandonResources() {
449     fVertShaderModule = VK_NULL_HANDLE;
450     fFragShaderModule = VK_NULL_HANDLE;
451     if (fPipelineLayout) {
452         fPipelineLayout->unrefAndAbandon();
453         fPipelineLayout = nullptr;
454     }
455 
456     if (fUniformBuffer) {
457         fUniformBuffer->abandon();
458         fUniformBuffer.reset();
459     }
460 }
461