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