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