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