blob: 938596ff0cbce0b80db8611990596342bd12c803 [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 Nicholas5af9ea32017-07-28 15:19:46 -040047 "mediump float4 uPosXform;"
48 "mediump float4 uTexCoordXform;"
egdanielbc9b2962016-09-27 08:00:53 -070049 "};"
Ethan Nicholas5af9ea32017-07-28 15:19:46 -040050 "layout(location = 0) in highp float2 inPosition;"
51 "layout(location = 1) out mediump float2 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 Nicholas5af9ea32017-07-28 15:19:46 -040057 "gl_Position.zw = float2(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
66 "precision mediump float;"
67
68 "layout(set = 1, binding = 0) uniform mediump sampler2D uTextureSampler;"
Ethan Nicholas5af9ea32017-07-28 15:19:46 -040069 "layout(location = 1) in mediump float2 vTexCoord;"
70 "layout(location = 0, index = 0) out mediump float4 fsColorOut;"
egdanielbc9b2962016-09-27 08:00:53 -070071
72 "// Copy Program FS\n"
73 "void main() {"
74 "fsColorOut = texture(uTextureSampler, vTexCoord);"
75 "}"
76 );
77
Ethan Nicholas941e7e22016-12-12 15:33:30 -050078 SkSL::Program::Settings settings;
79 SkSL::Program::Inputs inputs;
80 if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(), VK_SHADER_STAGE_VERTEX_BIT,
81 &fVertShaderModule, &fShaderStageInfo[0], settings, &inputs)) {
egdanielbc9b2962016-09-27 08:00:53 -070082 this->destroyResources(gpu);
83 return false;
84 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -050085 SkASSERT(inputs.isEmpty());
egdanielbc9b2962016-09-27 08:00:53 -070086
Ethan Nicholas941e7e22016-12-12 15:33:30 -050087 if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT,
88 &fFragShaderModule, &fShaderStageInfo[1], settings, &inputs)) {
egdanielbc9b2962016-09-27 08:00:53 -070089 this->destroyResources(gpu);
90 return false;
91 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -050092 SkASSERT(inputs.isEmpty());
egdanielbc9b2962016-09-27 08:00:53 -070093
94 VkDescriptorSetLayout dsLayout[2];
95
96 GrVkResourceProvider& resourceProvider = gpu->resourceProvider();
97
98 dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout();
99
100 uint32_t samplerVisibility = kFragment_GrShaderFlag;
101 SkTArray<uint32_t> visibilityArray(&samplerVisibility, 1);
102
Greg Daniela7543782017-05-02 14:01:43 -0400103 resourceProvider.getSamplerDescriptorSetHandle(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
104 visibilityArray, &fSamplerDSHandle);
egdanielbc9b2962016-09-27 08:00:53 -0700105 dsLayout[GrVkUniformHandler::kSamplerDescSet] =
106 resourceProvider.getSamplerDSLayout(fSamplerDSHandle);
107
108 // Create the VkPipelineLayout
109 VkPipelineLayoutCreateInfo layoutCreateInfo;
110 memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags));
111 layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
112 layoutCreateInfo.pNext = 0;
113 layoutCreateInfo.flags = 0;
114 layoutCreateInfo.setLayoutCount = 2;
115 layoutCreateInfo.pSetLayouts = dsLayout;
116 layoutCreateInfo.pushConstantRangeCount = 0;
117 layoutCreateInfo.pPushConstantRanges = nullptr;
118
119 VkResult err = GR_VK_CALL(gpu->vkInterface(), CreatePipelineLayout(gpu->device(),
120 &layoutCreateInfo,
121 nullptr,
122 &fPipelineLayout));
123 if (err) {
124 this->destroyResources(gpu);
125 return false;
126 }
127
128 static const float vdata[] = {
129 0, 0,
130 0, 1,
131 1, 0,
132 1, 1
133 };
134 fVertexBuffer.reset(GrVkVertexBuffer::Create(gpu, sizeof(vdata), false));
135 SkASSERT(fVertexBuffer.get());
136 fVertexBuffer->updateData(vdata, sizeof(vdata));
137
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400138 // We use 2 float4's for uniforms
Greg Danielf9f27232017-01-06 14:40:08 -0500139 fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, 8 * sizeof(float)));
140 SkASSERT(fUniformBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700141
142 return true;
143}
144
145bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu,
146 GrSurface* dst,
147 GrSurface* src,
148 const SkIRect& srcRect,
149 const SkIPoint& dstPoint) {
Greg Daniel6c9f1012017-05-11 09:20:59 -0400150 // None of our copy methods can handle a swizzle. TODO: Make copySurfaceAsDraw handle the
151 // swizzle.
152 if (gpu->caps()->shaderCaps()->configOutputSwizzle(src->config()) !=
153 gpu->caps()->shaderCaps()->configOutputSwizzle(dst->config())) {
154 return false;
155 }
156
egdanielbc9b2962016-09-27 08:00:53 -0700157 if (!gpu->vkCaps().supportsCopiesAsDraws()) {
158 return false;
159 }
160
Greg Daniele3cd6912017-05-17 11:15:55 -0400161 if (gpu->vkCaps().newCBOnPipelineChange()) {
162 // We bind a new pipeline here for the copy so we must start a new command buffer.
Mike Reed8724b462017-07-22 17:33:48 +0000163 gpu->finishFlush();
Greg Daniele3cd6912017-05-17 11:15:55 -0400164 }
165
egdanielbc9b2962016-09-27 08:00:53 -0700166 GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(dst->asRenderTarget());
167 if (!rt) {
168 return false;
169 }
170
171 GrVkTexture* srcTex = static_cast<GrVkTexture*>(src->asTexture());
172 if (!srcTex) {
173 return false;
174 }
175
176 if (VK_NULL_HANDLE == fVertShaderModule) {
177 SkASSERT(VK_NULL_HANDLE == fFragShaderModule &&
178 VK_NULL_HANDLE == fPipelineLayout &&
179 nullptr == fVertexBuffer.get() &&
Greg Danielf9f27232017-01-06 14:40:08 -0500180 nullptr == fUniformBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700181 if (!this->createCopyProgram(gpu)) {
182 SkDebugf("Failed to create copy program.\n");
183 return false;
184 }
185 }
186
187 GrVkResourceProvider& resourceProv = gpu->resourceProvider();
188
189 GrVkCopyPipeline* pipeline = resourceProv.findOrCreateCopyPipeline(rt,
190 fShaderStageInfo,
191 fPipelineLayout);
192 if (!pipeline) {
193 return false;
194 }
195
196 // UPDATE UNIFORM DESCRIPTOR SET
197 int w = srcRect.width();
198 int h = srcRect.height();
199
200 // dst rect edges in NDC (-1 to 1)
201 int dw = dst->width();
202 int dh = dst->height();
203 float dx0 = 2.f * dstPoint.fX / dw - 1.f;
204 float dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f;
205 float dy0 = 2.f * dstPoint.fY / dh - 1.f;
206 float dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f;
207 if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
208 dy0 = -dy0;
209 dy1 = -dy1;
210 }
211
212
213 float sx0 = (float)srcRect.fLeft;
214 float sx1 = (float)(srcRect.fLeft + w);
215 float sy0 = (float)srcRect.fTop;
216 float sy1 = (float)(srcRect.fTop + h);
217 int sh = src->height();
218 if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
219 sy0 = sh - sy0;
220 sy1 = sh - sy1;
221 }
222 // src rect edges in normalized texture space (0 to 1).
223 int sw = src->width();
224 sx0 /= sw;
225 sx1 /= sw;
226 sy0 /= sh;
227 sy1 /= sh;
228
229 float uniData[] = { dx1 - dx0, dy1 - dy0, dx0, dy0, // posXform
230 sx1 - sx0, sy1 - sy0, sx0, sy0 }; // texCoordXform
231
232 fUniformBuffer->updateData(gpu, uniData, sizeof(uniData), nullptr);
233
234 const GrVkDescriptorSet* uniformDS = resourceProv.getUniformDescriptorSet();
235 SkASSERT(uniformDS);
236
237 VkDescriptorBufferInfo uniBufferInfo;
238 uniBufferInfo.buffer = fUniformBuffer->buffer();
239 uniBufferInfo.offset = fUniformBuffer->offset();
240 uniBufferInfo.range = fUniformBuffer->size();
241
242 VkWriteDescriptorSet descriptorWrites;
243 descriptorWrites.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
244 descriptorWrites.pNext = nullptr;
245 descriptorWrites.dstSet = uniformDS->descriptorSet();
Greg Daniel18f96022017-05-04 15:09:03 -0400246 descriptorWrites.dstBinding = GrVkUniformHandler::kGeometryBinding;
egdanielbc9b2962016-09-27 08:00:53 -0700247 descriptorWrites.dstArrayElement = 0;
248 descriptorWrites.descriptorCount = 1;
249 descriptorWrites.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
250 descriptorWrites.pImageInfo = nullptr;
251 descriptorWrites.pBufferInfo = &uniBufferInfo;
252 descriptorWrites.pTexelBufferView = nullptr;
253
254 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
255 1,
256 &descriptorWrites,
257 0, nullptr));
258
259 // UPDATE SAMPLER DESCRIPTOR SET
260 const GrVkDescriptorSet* samplerDS =
261 gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle);
262
Brian Salomon514baff2016-11-17 15:17:07 -0500263 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
egdanielbc9b2962016-09-27 08:00:53 -0700264
265 GrVkSampler* sampler =
266 resourceProv.findOrCreateCompatibleSampler(params, srcTex->texturePriv().maxMipMapLevel());
267
268 VkDescriptorImageInfo imageInfo;
269 memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
270 imageInfo.sampler = sampler->sampler();
271 imageInfo.imageView = srcTex->textureView(true)->imageView();
272 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
273
274 VkWriteDescriptorSet writeInfo;
275 memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet));
276 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
277 writeInfo.pNext = nullptr;
278 writeInfo.dstSet = samplerDS->descriptorSet();
279 writeInfo.dstBinding = 0;
280 writeInfo.dstArrayElement = 0;
281 writeInfo.descriptorCount = 1;
282 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
283 writeInfo.pImageInfo = &imageInfo;
284 writeInfo.pBufferInfo = nullptr;
285 writeInfo.pTexelBufferView = nullptr;
286
287 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
288 1,
289 &writeInfo,
290 0, nullptr));
291
292 VkDescriptorSet vkDescSets[] = { uniformDS->descriptorSet(), samplerDS->descriptorSet() };
293
294 GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(srcTex->asRenderTarget());
295 if (texRT) {
296 gpu->onResolveRenderTarget(texRT);
297 }
298
299 GrVkPrimaryCommandBuffer* cmdBuffer = gpu->currentCommandBuffer();
300
301 // TODO: Make tighter bounds and then adjust bounds for origin and granularity if we see
302 // any perf issues with using the whole bounds
303 SkIRect bounds = SkIRect::MakeWH(rt->width(), rt->height());
304
305 // Change layouts of rt and texture
306 GrVkImage* targetImage = rt->msaaImage() ? rt->msaaImage() : rt;
307 targetImage->setImageLayout(gpu,
308 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
309 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
310 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
311 false);
312
313 srcTex->setImageLayout(gpu,
314 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
315 VK_ACCESS_SHADER_READ_BIT,
316 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
317 false);
318
319 GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE,
320 VK_ATTACHMENT_STORE_OP_STORE);
Greg Danielac95c5f2017-01-30 16:33:57 -0500321 GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD,
egdanielbc9b2962016-09-27 08:00:53 -0700322 VK_ATTACHMENT_STORE_OP_STORE);
egdanielbc9b2962016-09-27 08:00:53 -0700323 const GrVkRenderPass* renderPass;
324 const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
325 rt->compatibleRenderPassHandle();
326 if (rpHandle.isValid()) {
327 renderPass = gpu->resourceProvider().findRenderPass(rpHandle,
328 vkColorOps,
egdanielbc9b2962016-09-27 08:00:53 -0700329 vkStencilOps);
330 } else {
331 renderPass = gpu->resourceProvider().findRenderPass(*rt,
332 vkColorOps,
egdanielbc9b2962016-09-27 08:00:53 -0700333 vkStencilOps);
334 }
335
336 SkASSERT(renderPass->isCompatible(*rt->simpleRenderPass()));
337
338
Greg Daniel77a86f82017-01-23 11:04:45 -0500339 cmdBuffer->beginRenderPass(gpu, renderPass, nullptr, *rt, bounds, false);
egdanielbc9b2962016-09-27 08:00:53 -0700340 cmdBuffer->bindPipeline(gpu, pipeline);
341
342 // Uniform DescriptorSet, Sampler DescriptorSet, and vertex shader uniformBuffer
343 SkSTArray<3, const GrVkRecycledResource*> descriptorRecycledResources;
344 descriptorRecycledResources.push_back(uniformDS);
345 descriptorRecycledResources.push_back(samplerDS);
346 descriptorRecycledResources.push_back(fUniformBuffer->resource());
347
348 // One sampler, texture view, and texture
349 SkSTArray<3, const GrVkResource*> descriptorResources;
350 descriptorResources.push_back(sampler);
351 descriptorResources.push_back(srcTex->textureView(true));
352 descriptorResources.push_back(srcTex->resource());
353
354 cmdBuffer->bindDescriptorSets(gpu,
355 descriptorRecycledResources,
356 descriptorResources,
357 fPipelineLayout,
358 0,
359 2,
360 vkDescSets,
361 0,
362 nullptr);
363
364 // Set Dynamic viewport and stencil
365 // We always use one viewport the size of the RT
366 VkViewport viewport;
367 viewport.x = 0.0f;
368 viewport.y = 0.0f;
369 viewport.width = SkIntToScalar(rt->width());
370 viewport.height = SkIntToScalar(rt->height());
371 viewport.minDepth = 0.0f;
372 viewport.maxDepth = 1.0f;
373 cmdBuffer->setViewport(gpu, 0, 1, &viewport);
374
375 // We assume the scissor is not enabled so just set it to the whole RT
376 VkRect2D scissor;
377 scissor.extent.width = rt->width();
378 scissor.extent.height = rt->height();
379 scissor.offset.x = 0;
380 scissor.offset.y = 0;
381 cmdBuffer->setScissor(gpu, 0, 1, &scissor);
382
Chris Dalton1d616352017-05-31 12:51:23 -0600383 cmdBuffer->bindInputBuffer(gpu, 0, fVertexBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700384 cmdBuffer->draw(gpu, 4, 1, 0, 0);
385 cmdBuffer->endRenderPass(gpu);
386
387 // Release all temp resources which should now be reffed by the cmd buffer
388 pipeline->unref(gpu);
389 uniformDS->unref(gpu);
390 samplerDS->unref(gpu);
391 sampler->unref(gpu);
392 renderPass->unref(gpu);
393
394 return true;
395}
396
397void GrVkCopyManager::destroyResources(GrVkGpu* gpu) {
398 if (VK_NULL_HANDLE != fVertShaderModule) {
399 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fVertShaderModule,
400 nullptr));
401 fVertShaderModule = VK_NULL_HANDLE;
402 }
403
404 if (VK_NULL_HANDLE != fFragShaderModule) {
405 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fFragShaderModule,
406 nullptr));
407 fFragShaderModule = VK_NULL_HANDLE;
408 }
409
410 if (VK_NULL_HANDLE != fPipelineLayout) {
411 GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(), fPipelineLayout,
412 nullptr));
413 fPipelineLayout = VK_NULL_HANDLE;
414 }
415
416 if (fUniformBuffer) {
417 fUniformBuffer->release(gpu);
Greg Danielf9f27232017-01-06 14:40:08 -0500418 fUniformBuffer.reset();
egdanielbc9b2962016-09-27 08:00:53 -0700419 }
420}
421
422void GrVkCopyManager::abandonResources() {
423 fVertShaderModule = VK_NULL_HANDLE;
424 fFragShaderModule = VK_NULL_HANDLE;
425 fPipelineLayout = VK_NULL_HANDLE;
426
427 if (fUniformBuffer) {
428 fUniformBuffer->abandon();
Greg Danielf9f27232017-01-06 14:40:08 -0500429 fUniformBuffer.reset();
egdanielbc9b2962016-09-27 08:00:53 -0700430 }
431}