blob: 11ee12944811892aebb925812d2919d7611d7eda [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"
Ryan Macnak38a10ad2017-07-10 10:36:34 -070027#include "SkTraceEvent.h"
egdanielbc9b2962016-09-27 08:00:53 -070028
Greg Danielf9f27232017-01-06 14:40:08 -050029GrVkCopyManager::GrVkCopyManager()
30 : fVertShaderModule(VK_NULL_HANDLE)
31 , fFragShaderModule(VK_NULL_HANDLE)
32 , fPipelineLayout(VK_NULL_HANDLE) {}
33
34GrVkCopyManager::~GrVkCopyManager() {}
35
egdanielbc9b2962016-09-27 08:00:53 -070036bool GrVkCopyManager::createCopyProgram(GrVkGpu* gpu) {
Brian Osman39c08ac2017-07-26 09:36:09 -040037 TRACE_EVENT0("skia", TRACE_FUNC);
Ryan Macnak38a10ad2017-07-10 10:36:34 -070038
Brian Salomon1edc5b92016-11-29 13:43:46 -050039 const GrShaderCaps* shaderCaps = gpu->caps()->shaderCaps();
40 const char* version = shaderCaps->versionDeclString();
egdanielbc9b2962016-09-27 08:00:53 -070041 SkString vertShaderText(version);
42 vertShaderText.append(
43 "#extension GL_ARB_separate_shader_objects : enable\n"
44 "#extension GL_ARB_shading_language_420pack : enable\n"
45
46 "layout(set = 0, binding = 0) uniform vertexUniformBuffer {"
Ethan Nicholas88d99c62017-08-16 16:41:30 -040047 "half4 uPosXform;"
48 "half4 uTexCoordXform;"
egdanielbc9b2962016-09-27 08:00:53 -070049 "};"
Ethan Nicholas88d99c62017-08-16 16:41:30 -040050 "layout(location = 0) in highfloat2 inPosition;"
51 "layout(location = 1) out half2 vTexCoord;"
egdanielbc9b2962016-09-27 08:00:53 -070052
53 "// Copy Program VS\n"
54 "void main() {"
55 "vTexCoord = inPosition * uTexCoordXform.xy + uTexCoordXform.zw;"
56 "gl_Position.xy = inPosition * uPosXform.xy + uPosXform.zw;"
Ethan Nicholas88d99c62017-08-16 16:41:30 -040057 "gl_Position.zw = half2(0, 1);"
egdanielbc9b2962016-09-27 08:00:53 -070058 "}"
59 );
60
61 SkString fragShaderText(version);
62 fragShaderText.append(
63 "#extension GL_ARB_separate_shader_objects : enable\n"
64 "#extension GL_ARB_shading_language_420pack : enable\n"
65
Ethan Nicholas88d99c62017-08-16 16:41:30 -040066 "layout(set = 1, binding = 0) uniform sampler2D uTextureSampler;"
67 "layout(location = 1) in half2 vTexCoord;"
68 "layout(location = 0, index = 0) out half4 fsColorOut;"
egdanielbc9b2962016-09-27 08:00:53 -070069
70 "// Copy Program FS\n"
71 "void main() {"
72 "fsColorOut = texture(uTextureSampler, vTexCoord);"
73 "}"
74 );
75
Ethan Nicholas941e7e22016-12-12 15:33:30 -050076 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)) {
egdanielbc9b2962016-09-27 08:00:53 -070080 this->destroyResources(gpu);
81 return false;
82 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -050083 SkASSERT(inputs.isEmpty());
egdanielbc9b2962016-09-27 08:00:53 -070084
Ethan Nicholas941e7e22016-12-12 15:33:30 -050085 if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT,
86 &fFragShaderModule, &fShaderStageInfo[1], settings, &inputs)) {
egdanielbc9b2962016-09-27 08:00:53 -070087 this->destroyResources(gpu);
88 return false;
89 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -050090 SkASSERT(inputs.isEmpty());
egdanielbc9b2962016-09-27 08:00:53 -070091
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
Greg Daniela7543782017-05-02 14:01:43 -0400101 resourceProvider.getSamplerDescriptorSetHandle(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
102 visibilityArray, &fSamplerDSHandle);
egdanielbc9b2962016-09-27 08:00:53 -0700103 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
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400136 // We use 2 float4's for uniforms
Greg Danielf9f27232017-01-06 14:40:08 -0500137 fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, 8 * sizeof(float)));
138 SkASSERT(fUniformBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700139
140 return true;
141}
142
143bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu,
Robert Phillips7294b852017-08-01 13:51:44 +0000144 GrSurface* dst,
145 GrSurface* src,
146 const SkIRect& srcRect,
147 const SkIPoint& dstPoint) {
Greg Daniel6c9f1012017-05-11 09:20:59 -0400148 // 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
egdanielbc9b2962016-09-27 08:00:53 -0700155 if (!gpu->vkCaps().supportsCopiesAsDraws()) {
156 return false;
157 }
158
Greg Daniele3cd6912017-05-17 11:15:55 -0400159 if (gpu->vkCaps().newCBOnPipelineChange()) {
160 // We bind a new pipeline here for the copy so we must start a new command buffer.
Greg Daniel51316782017-08-02 15:10:09 +0000161 gpu->finishFlush(0, nullptr);
Greg Daniele3cd6912017-05-17 11:15:55 -0400162 }
163
egdanielbc9b2962016-09-27 08:00:53 -0700164 GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(dst->asRenderTarget());
165 if (!rt) {
166 return false;
167 }
168
169 GrVkTexture* srcTex = static_cast<GrVkTexture*>(src->asTexture());
170 if (!srcTex) {
171 return false;
172 }
173
174 if (VK_NULL_HANDLE == fVertShaderModule) {
175 SkASSERT(VK_NULL_HANDLE == fFragShaderModule &&
176 VK_NULL_HANDLE == fPipelineLayout &&
177 nullptr == fVertexBuffer.get() &&
Greg Danielf9f27232017-01-06 14:40:08 -0500178 nullptr == fUniformBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700179 if (!this->createCopyProgram(gpu)) {
180 SkDebugf("Failed to create copy program.\n");
181 return false;
182 }
183 }
184
185 GrVkResourceProvider& resourceProv = gpu->resourceProvider();
186
187 GrVkCopyPipeline* pipeline = resourceProv.findOrCreateCopyPipeline(rt,
188 fShaderStageInfo,
189 fPipelineLayout);
190 if (!pipeline) {
191 return false;
192 }
193
194 // UPDATE UNIFORM DESCRIPTOR SET
195 int w = srcRect.width();
196 int h = srcRect.height();
197
198 // dst rect edges in NDC (-1 to 1)
199 int dw = dst->width();
200 int dh = dst->height();
201 float dx0 = 2.f * dstPoint.fX / dw - 1.f;
202 float dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f;
203 float dy0 = 2.f * dstPoint.fY / dh - 1.f;
204 float dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f;
Robert Phillips7294b852017-08-01 13:51:44 +0000205 if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
egdanielbc9b2962016-09-27 08:00:53 -0700206 dy0 = -dy0;
207 dy1 = -dy1;
208 }
209
210
211 float sx0 = (float)srcRect.fLeft;
212 float sx1 = (float)(srcRect.fLeft + w);
213 float sy0 = (float)srcRect.fTop;
214 float sy1 = (float)(srcRect.fTop + h);
215 int sh = src->height();
Robert Phillips7294b852017-08-01 13:51:44 +0000216 if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
egdanielbc9b2962016-09-27 08:00:53 -0700217 sy0 = sh - sy0;
218 sy1 = sh - sy1;
219 }
220 // src rect edges in normalized texture space (0 to 1).
221 int sw = src->width();
222 sx0 /= sw;
223 sx1 /= sw;
224 sy0 /= sh;
225 sy1 /= sh;
226
227 float uniData[] = { dx1 - dx0, dy1 - dy0, dx0, dy0, // posXform
228 sx1 - sx0, sy1 - sy0, sx0, sy0 }; // texCoordXform
229
230 fUniformBuffer->updateData(gpu, uniData, sizeof(uniData), nullptr);
231
232 const GrVkDescriptorSet* uniformDS = resourceProv.getUniformDescriptorSet();
233 SkASSERT(uniformDS);
234
235 VkDescriptorBufferInfo uniBufferInfo;
236 uniBufferInfo.buffer = fUniformBuffer->buffer();
237 uniBufferInfo.offset = fUniformBuffer->offset();
238 uniBufferInfo.range = fUniformBuffer->size();
239
240 VkWriteDescriptorSet descriptorWrites;
241 descriptorWrites.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
242 descriptorWrites.pNext = nullptr;
243 descriptorWrites.dstSet = uniformDS->descriptorSet();
Greg Daniel18f96022017-05-04 15:09:03 -0400244 descriptorWrites.dstBinding = GrVkUniformHandler::kGeometryBinding;
egdanielbc9b2962016-09-27 08:00:53 -0700245 descriptorWrites.dstArrayElement = 0;
246 descriptorWrites.descriptorCount = 1;
247 descriptorWrites.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
248 descriptorWrites.pImageInfo = nullptr;
249 descriptorWrites.pBufferInfo = &uniBufferInfo;
250 descriptorWrites.pTexelBufferView = nullptr;
251
252 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
253 1,
254 &descriptorWrites,
255 0, nullptr));
256
257 // UPDATE SAMPLER DESCRIPTOR SET
258 const GrVkDescriptorSet* samplerDS =
259 gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle);
260
Brian Salomon514baff2016-11-17 15:17:07 -0500261 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
egdanielbc9b2962016-09-27 08:00:53 -0700262
263 GrVkSampler* sampler =
264 resourceProv.findOrCreateCompatibleSampler(params, srcTex->texturePriv().maxMipMapLevel());
265
266 VkDescriptorImageInfo imageInfo;
267 memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
268 imageInfo.sampler = sampler->sampler();
269 imageInfo.imageView = srcTex->textureView(true)->imageView();
270 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
271
272 VkWriteDescriptorSet writeInfo;
273 memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet));
274 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
275 writeInfo.pNext = nullptr;
276 writeInfo.dstSet = samplerDS->descriptorSet();
277 writeInfo.dstBinding = 0;
278 writeInfo.dstArrayElement = 0;
279 writeInfo.descriptorCount = 1;
280 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
281 writeInfo.pImageInfo = &imageInfo;
282 writeInfo.pBufferInfo = nullptr;
283 writeInfo.pTexelBufferView = nullptr;
284
285 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
286 1,
287 &writeInfo,
288 0, nullptr));
289
290 VkDescriptorSet vkDescSets[] = { uniformDS->descriptorSet(), samplerDS->descriptorSet() };
291
292 GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(srcTex->asRenderTarget());
293 if (texRT) {
Robert Phillips7294b852017-08-01 13:51:44 +0000294 gpu->onResolveRenderTarget(texRT);
egdanielbc9b2962016-09-27 08:00:53 -0700295 }
296
297 GrVkPrimaryCommandBuffer* cmdBuffer = gpu->currentCommandBuffer();
298
299 // TODO: Make tighter bounds and then adjust bounds for origin and granularity if we see
300 // any perf issues with using the whole bounds
301 SkIRect bounds = SkIRect::MakeWH(rt->width(), rt->height());
302
303 // Change layouts of rt and texture
304 GrVkImage* targetImage = rt->msaaImage() ? rt->msaaImage() : rt;
305 targetImage->setImageLayout(gpu,
306 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
307 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
308 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
309 false);
310
311 srcTex->setImageLayout(gpu,
312 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
313 VK_ACCESS_SHADER_READ_BIT,
314 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
315 false);
316
317 GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE,
318 VK_ATTACHMENT_STORE_OP_STORE);
Greg Danielac95c5f2017-01-30 16:33:57 -0500319 GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD,
egdanielbc9b2962016-09-27 08:00:53 -0700320 VK_ATTACHMENT_STORE_OP_STORE);
egdanielbc9b2962016-09-27 08:00:53 -0700321 const GrVkRenderPass* renderPass;
322 const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
323 rt->compatibleRenderPassHandle();
324 if (rpHandle.isValid()) {
325 renderPass = gpu->resourceProvider().findRenderPass(rpHandle,
326 vkColorOps,
egdanielbc9b2962016-09-27 08:00:53 -0700327 vkStencilOps);
328 } else {
329 renderPass = gpu->resourceProvider().findRenderPass(*rt,
330 vkColorOps,
egdanielbc9b2962016-09-27 08:00:53 -0700331 vkStencilOps);
332 }
333
334 SkASSERT(renderPass->isCompatible(*rt->simpleRenderPass()));
335
336
Greg Daniel77a86f82017-01-23 11:04:45 -0500337 cmdBuffer->beginRenderPass(gpu, renderPass, nullptr, *rt, bounds, false);
egdanielbc9b2962016-09-27 08:00:53 -0700338 cmdBuffer->bindPipeline(gpu, pipeline);
339
340 // Uniform DescriptorSet, Sampler DescriptorSet, and vertex shader uniformBuffer
341 SkSTArray<3, const GrVkRecycledResource*> descriptorRecycledResources;
342 descriptorRecycledResources.push_back(uniformDS);
343 descriptorRecycledResources.push_back(samplerDS);
344 descriptorRecycledResources.push_back(fUniformBuffer->resource());
345
346 // One sampler, texture view, and texture
347 SkSTArray<3, const GrVkResource*> descriptorResources;
348 descriptorResources.push_back(sampler);
349 descriptorResources.push_back(srcTex->textureView(true));
350 descriptorResources.push_back(srcTex->resource());
351
352 cmdBuffer->bindDescriptorSets(gpu,
353 descriptorRecycledResources,
354 descriptorResources,
355 fPipelineLayout,
356 0,
357 2,
358 vkDescSets,
359 0,
360 nullptr);
361
362 // Set Dynamic viewport and stencil
363 // We always use one viewport the size of the RT
364 VkViewport viewport;
365 viewport.x = 0.0f;
366 viewport.y = 0.0f;
367 viewport.width = SkIntToScalar(rt->width());
368 viewport.height = SkIntToScalar(rt->height());
369 viewport.minDepth = 0.0f;
370 viewport.maxDepth = 1.0f;
371 cmdBuffer->setViewport(gpu, 0, 1, &viewport);
372
373 // We assume the scissor is not enabled so just set it to the whole RT
374 VkRect2D scissor;
375 scissor.extent.width = rt->width();
376 scissor.extent.height = rt->height();
377 scissor.offset.x = 0;
378 scissor.offset.y = 0;
379 cmdBuffer->setScissor(gpu, 0, 1, &scissor);
380
Chris Dalton1d616352017-05-31 12:51:23 -0600381 cmdBuffer->bindInputBuffer(gpu, 0, fVertexBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700382 cmdBuffer->draw(gpu, 4, 1, 0, 0);
383 cmdBuffer->endRenderPass(gpu);
384
385 // Release all temp resources which should now be reffed by the cmd buffer
386 pipeline->unref(gpu);
387 uniformDS->unref(gpu);
388 samplerDS->unref(gpu);
389 sampler->unref(gpu);
390 renderPass->unref(gpu);
391
392 return true;
393}
394
395void GrVkCopyManager::destroyResources(GrVkGpu* gpu) {
396 if (VK_NULL_HANDLE != fVertShaderModule) {
397 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fVertShaderModule,
398 nullptr));
399 fVertShaderModule = VK_NULL_HANDLE;
400 }
401
402 if (VK_NULL_HANDLE != fFragShaderModule) {
403 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fFragShaderModule,
404 nullptr));
405 fFragShaderModule = VK_NULL_HANDLE;
406 }
407
408 if (VK_NULL_HANDLE != fPipelineLayout) {
409 GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(), fPipelineLayout,
410 nullptr));
411 fPipelineLayout = VK_NULL_HANDLE;
412 }
413
414 if (fUniformBuffer) {
415 fUniformBuffer->release(gpu);
Greg Danielf9f27232017-01-06 14:40:08 -0500416 fUniformBuffer.reset();
egdanielbc9b2962016-09-27 08:00:53 -0700417 }
418}
419
420void GrVkCopyManager::abandonResources() {
421 fVertShaderModule = VK_NULL_HANDLE;
422 fFragShaderModule = VK_NULL_HANDLE;
423 fPipelineLayout = VK_NULL_HANDLE;
424
425 if (fUniformBuffer) {
426 fUniformBuffer->abandon();
Greg Danielf9f27232017-01-06 14:40:08 -0500427 fUniformBuffer.reset();
egdanielbc9b2962016-09-27 08:00:53 -0700428 }
429}