blob: cd5dba4b18b37d383fb300e31a970f2783d5ea5a [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
Greg Danielf9f27232017-01-06 14:40:08 -050028GrVkCopyManager::GrVkCopyManager()
29 : fVertShaderModule(VK_NULL_HANDLE)
30 , fFragShaderModule(VK_NULL_HANDLE)
31 , fPipelineLayout(VK_NULL_HANDLE) {}
32
33GrVkCopyManager::~GrVkCopyManager() {}
34
egdanielbc9b2962016-09-27 08:00:53 -070035bool GrVkCopyManager::createCopyProgram(GrVkGpu* gpu) {
Brian Salomon1edc5b92016-11-29 13:43:46 -050036 const GrShaderCaps* shaderCaps = gpu->caps()->shaderCaps();
37 const char* version = shaderCaps->versionDeclString();
egdanielbc9b2962016-09-27 08:00:53 -070038 SkString vertShaderText(version);
39 vertShaderText.append(
40 "#extension GL_ARB_separate_shader_objects : enable\n"
41 "#extension GL_ARB_shading_language_420pack : enable\n"
42
43 "layout(set = 0, binding = 0) uniform vertexUniformBuffer {"
44 "mediump vec4 uPosXform;"
45 "mediump vec4 uTexCoordXform;"
46 "};"
47 "layout(location = 0) in highp vec2 inPosition;"
48 "layout(location = 1) out mediump vec2 vTexCoord;"
49
50 "// Copy Program VS\n"
51 "void main() {"
52 "vTexCoord = inPosition * uTexCoordXform.xy + uTexCoordXform.zw;"
53 "gl_Position.xy = inPosition * uPosXform.xy + uPosXform.zw;"
54 "gl_Position.zw = vec2(0, 1);"
55 "}"
56 );
57
58 SkString fragShaderText(version);
59 fragShaderText.append(
60 "#extension GL_ARB_separate_shader_objects : enable\n"
61 "#extension GL_ARB_shading_language_420pack : enable\n"
62
63 "precision mediump float;"
64
65 "layout(set = 1, binding = 0) uniform mediump sampler2D uTextureSampler;"
66 "layout(location = 1) in mediump vec2 vTexCoord;"
67 "layout(location = 0, index = 0) out mediump vec4 fsColorOut;"
68
69 "// Copy Program FS\n"
70 "void main() {"
71 "fsColorOut = texture(uTextureSampler, vTexCoord);"
72 "}"
73 );
74
Ethan Nicholas941e7e22016-12-12 15:33:30 -050075 SkSL::Program::Settings settings;
76 SkSL::Program::Inputs inputs;
77 if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(), VK_SHADER_STAGE_VERTEX_BIT,
78 &fVertShaderModule, &fShaderStageInfo[0], settings, &inputs)) {
egdanielbc9b2962016-09-27 08:00:53 -070079 this->destroyResources(gpu);
80 return false;
81 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -050082 SkASSERT(inputs.isEmpty());
egdanielbc9b2962016-09-27 08:00:53 -070083
Ethan Nicholas941e7e22016-12-12 15:33:30 -050084 if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT,
85 &fFragShaderModule, &fShaderStageInfo[1], settings, &inputs)) {
egdanielbc9b2962016-09-27 08:00:53 -070086 this->destroyResources(gpu);
87 return false;
88 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -050089 SkASSERT(inputs.isEmpty());
egdanielbc9b2962016-09-27 08:00:53 -070090
91 VkDescriptorSetLayout dsLayout[2];
92
93 GrVkResourceProvider& resourceProvider = gpu->resourceProvider();
94
95 dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout();
96
97 uint32_t samplerVisibility = kFragment_GrShaderFlag;
98 SkTArray<uint32_t> visibilityArray(&samplerVisibility, 1);
99
Greg Daniela7543782017-05-02 14:01:43 -0400100 resourceProvider.getSamplerDescriptorSetHandle(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
101 visibilityArray, &fSamplerDSHandle);
egdanielbc9b2962016-09-27 08:00:53 -0700102 dsLayout[GrVkUniformHandler::kSamplerDescSet] =
103 resourceProvider.getSamplerDSLayout(fSamplerDSHandle);
104
105 // Create the VkPipelineLayout
106 VkPipelineLayoutCreateInfo layoutCreateInfo;
107 memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags));
108 layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
109 layoutCreateInfo.pNext = 0;
110 layoutCreateInfo.flags = 0;
111 layoutCreateInfo.setLayoutCount = 2;
112 layoutCreateInfo.pSetLayouts = dsLayout;
113 layoutCreateInfo.pushConstantRangeCount = 0;
114 layoutCreateInfo.pPushConstantRanges = nullptr;
115
116 VkResult err = GR_VK_CALL(gpu->vkInterface(), CreatePipelineLayout(gpu->device(),
117 &layoutCreateInfo,
118 nullptr,
119 &fPipelineLayout));
120 if (err) {
121 this->destroyResources(gpu);
122 return false;
123 }
124
125 static const float vdata[] = {
126 0, 0,
127 0, 1,
128 1, 0,
129 1, 1
130 };
131 fVertexBuffer.reset(GrVkVertexBuffer::Create(gpu, sizeof(vdata), false));
132 SkASSERT(fVertexBuffer.get());
133 fVertexBuffer->updateData(vdata, sizeof(vdata));
134
135 // We use 2 vec4's for uniforms
Greg Danielf9f27232017-01-06 14:40:08 -0500136 fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, 8 * sizeof(float)));
137 SkASSERT(fUniformBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700138
139 return true;
140}
141
142bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu,
143 GrSurface* dst,
144 GrSurface* src,
145 const SkIRect& srcRect,
146 const SkIPoint& dstPoint) {
Greg Daniel6c9f1012017-05-11 09:20:59 -0400147 // None of our copy methods can handle a swizzle. TODO: Make copySurfaceAsDraw handle the
148 // swizzle.
149 if (gpu->caps()->shaderCaps()->configOutputSwizzle(src->config()) !=
150 gpu->caps()->shaderCaps()->configOutputSwizzle(dst->config())) {
151 return false;
152 }
153
egdanielbc9b2962016-09-27 08:00:53 -0700154 if (!gpu->vkCaps().supportsCopiesAsDraws()) {
155 return false;
156 }
157
Greg Daniele3cd6912017-05-17 11:15:55 -0400158 if (gpu->vkCaps().newCBOnPipelineChange()) {
159 // We bind a new pipeline here for the copy so we must start a new command buffer.
160 gpu->finishFlush();
161 }
162
egdanielbc9b2962016-09-27 08:00:53 -0700163 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 VK_NULL_HANDLE == fPipelineLayout &&
176 nullptr == fVertexBuffer.get() &&
Greg Danielf9f27232017-01-06 14:40:08 -0500177 nullptr == fUniformBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700178 if (!this->createCopyProgram(gpu)) {
179 SkDebugf("Failed to create copy program.\n");
180 return false;
181 }
182 }
183
184 GrVkResourceProvider& resourceProv = gpu->resourceProvider();
185
186 GrVkCopyPipeline* pipeline = resourceProv.findOrCreateCopyPipeline(rt,
187 fShaderStageInfo,
188 fPipelineLayout);
189 if (!pipeline) {
190 return false;
191 }
192
193 // UPDATE UNIFORM DESCRIPTOR SET
194 int w = srcRect.width();
195 int h = srcRect.height();
196
197 // dst rect edges in NDC (-1 to 1)
198 int dw = dst->width();
199 int dh = dst->height();
200 float dx0 = 2.f * dstPoint.fX / dw - 1.f;
201 float dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f;
202 float dy0 = 2.f * dstPoint.fY / dh - 1.f;
203 float dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f;
204 if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
205 dy0 = -dy0;
206 dy1 = -dy1;
207 }
208
209
210 float sx0 = (float)srcRect.fLeft;
211 float sx1 = (float)(srcRect.fLeft + w);
212 float sy0 = (float)srcRect.fTop;
213 float sy1 = (float)(srcRect.fTop + h);
214 int sh = src->height();
215 if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
216 sy0 = sh - sy0;
217 sy1 = sh - sy1;
218 }
219 // src rect edges in normalized texture space (0 to 1).
220 int sw = src->width();
221 sx0 /= sw;
222 sx1 /= sw;
223 sy0 /= sh;
224 sy1 /= sh;
225
226 float uniData[] = { dx1 - dx0, dy1 - dy0, dx0, dy0, // posXform
227 sx1 - sx0, sy1 - sy0, sx0, sy0 }; // texCoordXform
228
229 fUniformBuffer->updateData(gpu, uniData, sizeof(uniData), nullptr);
230
231 const GrVkDescriptorSet* uniformDS = resourceProv.getUniformDescriptorSet();
232 SkASSERT(uniformDS);
233
234 VkDescriptorBufferInfo uniBufferInfo;
235 uniBufferInfo.buffer = fUniformBuffer->buffer();
236 uniBufferInfo.offset = fUniformBuffer->offset();
237 uniBufferInfo.range = fUniformBuffer->size();
238
239 VkWriteDescriptorSet descriptorWrites;
240 descriptorWrites.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
241 descriptorWrites.pNext = nullptr;
242 descriptorWrites.dstSet = uniformDS->descriptorSet();
Greg Daniel18f96022017-05-04 15:09:03 -0400243 descriptorWrites.dstBinding = GrVkUniformHandler::kGeometryBinding;
egdanielbc9b2962016-09-27 08:00:53 -0700244 descriptorWrites.dstArrayElement = 0;
245 descriptorWrites.descriptorCount = 1;
246 descriptorWrites.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
247 descriptorWrites.pImageInfo = nullptr;
248 descriptorWrites.pBufferInfo = &uniBufferInfo;
249 descriptorWrites.pTexelBufferView = nullptr;
250
251 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
252 1,
253 &descriptorWrites,
254 0, nullptr));
255
256 // UPDATE SAMPLER DESCRIPTOR SET
257 const GrVkDescriptorSet* samplerDS =
258 gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle);
259
Brian Salomon514baff2016-11-17 15:17:07 -0500260 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
egdanielbc9b2962016-09-27 08:00:53 -0700261
262 GrVkSampler* sampler =
263 resourceProv.findOrCreateCompatibleSampler(params, srcTex->texturePriv().maxMipMapLevel());
264
265 VkDescriptorImageInfo imageInfo;
266 memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
267 imageInfo.sampler = sampler->sampler();
268 imageInfo.imageView = srcTex->textureView(true)->imageView();
269 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
270
271 VkWriteDescriptorSet writeInfo;
272 memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet));
273 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
274 writeInfo.pNext = nullptr;
275 writeInfo.dstSet = samplerDS->descriptorSet();
276 writeInfo.dstBinding = 0;
277 writeInfo.dstArrayElement = 0;
278 writeInfo.descriptorCount = 1;
279 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
280 writeInfo.pImageInfo = &imageInfo;
281 writeInfo.pBufferInfo = nullptr;
282 writeInfo.pTexelBufferView = nullptr;
283
284 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
285 1,
286 &writeInfo,
287 0, nullptr));
288
289 VkDescriptorSet vkDescSets[] = { uniformDS->descriptorSet(), samplerDS->descriptorSet() };
290
291 GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(srcTex->asRenderTarget());
292 if (texRT) {
293 gpu->onResolveRenderTarget(texRT);
294 }
295
296 GrVkPrimaryCommandBuffer* cmdBuffer = gpu->currentCommandBuffer();
297
298 // TODO: Make tighter bounds and then adjust bounds for origin and granularity if we see
299 // any perf issues with using the whole bounds
300 SkIRect bounds = SkIRect::MakeWH(rt->width(), rt->height());
301
302 // Change layouts of rt and texture
303 GrVkImage* targetImage = rt->msaaImage() ? rt->msaaImage() : rt;
304 targetImage->setImageLayout(gpu,
305 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
306 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
307 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
308 false);
309
310 srcTex->setImageLayout(gpu,
311 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
312 VK_ACCESS_SHADER_READ_BIT,
313 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
314 false);
315
316 GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE,
317 VK_ATTACHMENT_STORE_OP_STORE);
Greg Danielac95c5f2017-01-30 16:33:57 -0500318 GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD,
egdanielbc9b2962016-09-27 08:00:53 -0700319 VK_ATTACHMENT_STORE_OP_STORE);
egdanielbc9b2962016-09-27 08:00:53 -0700320 const GrVkRenderPass* renderPass;
321 const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
322 rt->compatibleRenderPassHandle();
323 if (rpHandle.isValid()) {
324 renderPass = gpu->resourceProvider().findRenderPass(rpHandle,
325 vkColorOps,
egdanielbc9b2962016-09-27 08:00:53 -0700326 vkStencilOps);
327 } else {
328 renderPass = gpu->resourceProvider().findRenderPass(*rt,
329 vkColorOps,
egdanielbc9b2962016-09-27 08:00:53 -0700330 vkStencilOps);
331 }
332
333 SkASSERT(renderPass->isCompatible(*rt->simpleRenderPass()));
334
335
Greg Daniel77a86f82017-01-23 11:04:45 -0500336 cmdBuffer->beginRenderPass(gpu, renderPass, nullptr, *rt, bounds, false);
egdanielbc9b2962016-09-27 08:00:53 -0700337 cmdBuffer->bindPipeline(gpu, pipeline);
338
339 // Uniform DescriptorSet, Sampler DescriptorSet, and vertex shader uniformBuffer
340 SkSTArray<3, const GrVkRecycledResource*> descriptorRecycledResources;
341 descriptorRecycledResources.push_back(uniformDS);
342 descriptorRecycledResources.push_back(samplerDS);
343 descriptorRecycledResources.push_back(fUniformBuffer->resource());
344
345 // One sampler, texture view, and texture
346 SkSTArray<3, const GrVkResource*> descriptorResources;
347 descriptorResources.push_back(sampler);
348 descriptorResources.push_back(srcTex->textureView(true));
349 descriptorResources.push_back(srcTex->resource());
350
351 cmdBuffer->bindDescriptorSets(gpu,
352 descriptorRecycledResources,
353 descriptorResources,
354 fPipelineLayout,
355 0,
356 2,
357 vkDescSets,
358 0,
359 nullptr);
360
361 // Set Dynamic viewport and stencil
362 // We always use one viewport the size of the RT
363 VkViewport viewport;
364 viewport.x = 0.0f;
365 viewport.y = 0.0f;
366 viewport.width = SkIntToScalar(rt->width());
367 viewport.height = SkIntToScalar(rt->height());
368 viewport.minDepth = 0.0f;
369 viewport.maxDepth = 1.0f;
370 cmdBuffer->setViewport(gpu, 0, 1, &viewport);
371
372 // We assume the scissor is not enabled so just set it to the whole RT
373 VkRect2D scissor;
374 scissor.extent.width = rt->width();
375 scissor.extent.height = rt->height();
376 scissor.offset.x = 0;
377 scissor.offset.y = 0;
378 cmdBuffer->setScissor(gpu, 0, 1, &scissor);
379
Chris Dalton1d616352017-05-31 12:51:23 -0600380 cmdBuffer->bindInputBuffer(gpu, 0, fVertexBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700381 cmdBuffer->draw(gpu, 4, 1, 0, 0);
382 cmdBuffer->endRenderPass(gpu);
383
384 // Release all temp resources which should now be reffed by the cmd buffer
385 pipeline->unref(gpu);
386 uniformDS->unref(gpu);
387 samplerDS->unref(gpu);
388 sampler->unref(gpu);
389 renderPass->unref(gpu);
390
391 return true;
392}
393
394void GrVkCopyManager::destroyResources(GrVkGpu* gpu) {
395 if (VK_NULL_HANDLE != fVertShaderModule) {
396 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fVertShaderModule,
397 nullptr));
398 fVertShaderModule = VK_NULL_HANDLE;
399 }
400
401 if (VK_NULL_HANDLE != fFragShaderModule) {
402 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fFragShaderModule,
403 nullptr));
404 fFragShaderModule = VK_NULL_HANDLE;
405 }
406
407 if (VK_NULL_HANDLE != fPipelineLayout) {
408 GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(), fPipelineLayout,
409 nullptr));
410 fPipelineLayout = VK_NULL_HANDLE;
411 }
412
413 if (fUniformBuffer) {
414 fUniformBuffer->release(gpu);
Greg Danielf9f27232017-01-06 14:40:08 -0500415 fUniformBuffer.reset();
egdanielbc9b2962016-09-27 08:00:53 -0700416 }
417}
418
419void GrVkCopyManager::abandonResources() {
420 fVertShaderModule = VK_NULL_HANDLE;
421 fFragShaderModule = VK_NULL_HANDLE;
422 fPipelineLayout = VK_NULL_HANDLE;
423
424 if (fUniformBuffer) {
425 fUniformBuffer->abandon();
Greg Danielf9f27232017-01-06 14:40:08 -0500426 fUniformBuffer.reset();
egdanielbc9b2962016-09-27 08:00:53 -0700427 }
428}