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