blob: b1f8f2a5e6d23a999d630e67032807a4855b6cfb [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
100 resourceProvider.getSamplerDescriptorSetHandle(visibilityArray, &fSamplerDSHandle);
101 dsLayout[GrVkUniformHandler::kSamplerDescSet] =
102 resourceProvider.getSamplerDSLayout(fSamplerDSHandle);
103
104 // Create the VkPipelineLayout
105 VkPipelineLayoutCreateInfo layoutCreateInfo;
106 memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags));
107 layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
108 layoutCreateInfo.pNext = 0;
109 layoutCreateInfo.flags = 0;
110 layoutCreateInfo.setLayoutCount = 2;
111 layoutCreateInfo.pSetLayouts = dsLayout;
112 layoutCreateInfo.pushConstantRangeCount = 0;
113 layoutCreateInfo.pPushConstantRanges = nullptr;
114
115 VkResult err = GR_VK_CALL(gpu->vkInterface(), CreatePipelineLayout(gpu->device(),
116 &layoutCreateInfo,
117 nullptr,
118 &fPipelineLayout));
119 if (err) {
120 this->destroyResources(gpu);
121 return false;
122 }
123
124 static const float vdata[] = {
125 0, 0,
126 0, 1,
127 1, 0,
128 1, 1
129 };
130 fVertexBuffer.reset(GrVkVertexBuffer::Create(gpu, sizeof(vdata), false));
131 SkASSERT(fVertexBuffer.get());
132 fVertexBuffer->updateData(vdata, sizeof(vdata));
133
134 // We use 2 vec4's for uniforms
Greg Danielf9f27232017-01-06 14:40:08 -0500135 fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, 8 * sizeof(float)));
136 SkASSERT(fUniformBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700137
138 return true;
139}
140
141bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu,
142 GrSurface* dst,
143 GrSurface* src,
144 const SkIRect& srcRect,
145 const SkIPoint& dstPoint) {
146 if (!gpu->vkCaps().supportsCopiesAsDraws()) {
147 return false;
148 }
149
150 GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(dst->asRenderTarget());
151 if (!rt) {
152 return false;
153 }
154
155 GrVkTexture* srcTex = static_cast<GrVkTexture*>(src->asTexture());
156 if (!srcTex) {
157 return false;
158 }
159
160 if (VK_NULL_HANDLE == fVertShaderModule) {
161 SkASSERT(VK_NULL_HANDLE == fFragShaderModule &&
162 VK_NULL_HANDLE == fPipelineLayout &&
163 nullptr == fVertexBuffer.get() &&
Greg Danielf9f27232017-01-06 14:40:08 -0500164 nullptr == fUniformBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700165 if (!this->createCopyProgram(gpu)) {
166 SkDebugf("Failed to create copy program.\n");
167 return false;
168 }
169 }
170
171 GrVkResourceProvider& resourceProv = gpu->resourceProvider();
172
173 GrVkCopyPipeline* pipeline = resourceProv.findOrCreateCopyPipeline(rt,
174 fShaderStageInfo,
175 fPipelineLayout);
176 if (!pipeline) {
177 return false;
178 }
179
180 // UPDATE UNIFORM DESCRIPTOR SET
181 int w = srcRect.width();
182 int h = srcRect.height();
183
184 // dst rect edges in NDC (-1 to 1)
185 int dw = dst->width();
186 int dh = dst->height();
187 float dx0 = 2.f * dstPoint.fX / dw - 1.f;
188 float dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f;
189 float dy0 = 2.f * dstPoint.fY / dh - 1.f;
190 float dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f;
191 if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
192 dy0 = -dy0;
193 dy1 = -dy1;
194 }
195
196
197 float sx0 = (float)srcRect.fLeft;
198 float sx1 = (float)(srcRect.fLeft + w);
199 float sy0 = (float)srcRect.fTop;
200 float sy1 = (float)(srcRect.fTop + h);
201 int sh = src->height();
202 if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
203 sy0 = sh - sy0;
204 sy1 = sh - sy1;
205 }
206 // src rect edges in normalized texture space (0 to 1).
207 int sw = src->width();
208 sx0 /= sw;
209 sx1 /= sw;
210 sy0 /= sh;
211 sy1 /= sh;
212
213 float uniData[] = { dx1 - dx0, dy1 - dy0, dx0, dy0, // posXform
214 sx1 - sx0, sy1 - sy0, sx0, sy0 }; // texCoordXform
215
216 fUniformBuffer->updateData(gpu, uniData, sizeof(uniData), nullptr);
217
218 const GrVkDescriptorSet* uniformDS = resourceProv.getUniformDescriptorSet();
219 SkASSERT(uniformDS);
220
221 VkDescriptorBufferInfo uniBufferInfo;
222 uniBufferInfo.buffer = fUniformBuffer->buffer();
223 uniBufferInfo.offset = fUniformBuffer->offset();
224 uniBufferInfo.range = fUniformBuffer->size();
225
226 VkWriteDescriptorSet descriptorWrites;
227 descriptorWrites.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
228 descriptorWrites.pNext = nullptr;
229 descriptorWrites.dstSet = uniformDS->descriptorSet();
230 descriptorWrites.dstBinding = GrVkUniformHandler::kVertexBinding;
231 descriptorWrites.dstArrayElement = 0;
232 descriptorWrites.descriptorCount = 1;
233 descriptorWrites.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
234 descriptorWrites.pImageInfo = nullptr;
235 descriptorWrites.pBufferInfo = &uniBufferInfo;
236 descriptorWrites.pTexelBufferView = nullptr;
237
238 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
239 1,
240 &descriptorWrites,
241 0, nullptr));
242
243 // UPDATE SAMPLER DESCRIPTOR SET
244 const GrVkDescriptorSet* samplerDS =
245 gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle);
246
Brian Salomon514baff2016-11-17 15:17:07 -0500247 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
egdanielbc9b2962016-09-27 08:00:53 -0700248
249 GrVkSampler* sampler =
250 resourceProv.findOrCreateCompatibleSampler(params, srcTex->texturePriv().maxMipMapLevel());
251
252 VkDescriptorImageInfo imageInfo;
253 memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
254 imageInfo.sampler = sampler->sampler();
255 imageInfo.imageView = srcTex->textureView(true)->imageView();
256 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
257
258 VkWriteDescriptorSet writeInfo;
259 memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet));
260 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
261 writeInfo.pNext = nullptr;
262 writeInfo.dstSet = samplerDS->descriptorSet();
263 writeInfo.dstBinding = 0;
264 writeInfo.dstArrayElement = 0;
265 writeInfo.descriptorCount = 1;
266 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
267 writeInfo.pImageInfo = &imageInfo;
268 writeInfo.pBufferInfo = nullptr;
269 writeInfo.pTexelBufferView = nullptr;
270
271 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
272 1,
273 &writeInfo,
274 0, nullptr));
275
276 VkDescriptorSet vkDescSets[] = { uniformDS->descriptorSet(), samplerDS->descriptorSet() };
277
278 GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(srcTex->asRenderTarget());
279 if (texRT) {
280 gpu->onResolveRenderTarget(texRT);
281 }
282
283 GrVkPrimaryCommandBuffer* cmdBuffer = gpu->currentCommandBuffer();
284
285 // TODO: Make tighter bounds and then adjust bounds for origin and granularity if we see
286 // any perf issues with using the whole bounds
287 SkIRect bounds = SkIRect::MakeWH(rt->width(), rt->height());
288
289 // Change layouts of rt and texture
290 GrVkImage* targetImage = rt->msaaImage() ? rt->msaaImage() : rt;
291 targetImage->setImageLayout(gpu,
292 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
293 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
294 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
295 false);
296
297 srcTex->setImageLayout(gpu,
298 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
299 VK_ACCESS_SHADER_READ_BIT,
300 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
301 false);
302
303 GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE,
304 VK_ATTACHMENT_STORE_OP_STORE);
305 GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE,
306 VK_ATTACHMENT_STORE_OP_STORE);
egdanielbc9b2962016-09-27 08:00:53 -0700307 const GrVkRenderPass* renderPass;
308 const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
309 rt->compatibleRenderPassHandle();
310 if (rpHandle.isValid()) {
311 renderPass = gpu->resourceProvider().findRenderPass(rpHandle,
312 vkColorOps,
egdanielbc9b2962016-09-27 08:00:53 -0700313 vkStencilOps);
314 } else {
315 renderPass = gpu->resourceProvider().findRenderPass(*rt,
316 vkColorOps,
egdanielbc9b2962016-09-27 08:00:53 -0700317 vkStencilOps);
318 }
319
320 SkASSERT(renderPass->isCompatible(*rt->simpleRenderPass()));
321
322
323 cmdBuffer->beginRenderPass(gpu, renderPass, 0, nullptr, *rt, bounds, false);
324 cmdBuffer->bindPipeline(gpu, pipeline);
325
326 // Uniform DescriptorSet, Sampler DescriptorSet, and vertex shader uniformBuffer
327 SkSTArray<3, const GrVkRecycledResource*> descriptorRecycledResources;
328 descriptorRecycledResources.push_back(uniformDS);
329 descriptorRecycledResources.push_back(samplerDS);
330 descriptorRecycledResources.push_back(fUniformBuffer->resource());
331
332 // One sampler, texture view, and texture
333 SkSTArray<3, const GrVkResource*> descriptorResources;
334 descriptorResources.push_back(sampler);
335 descriptorResources.push_back(srcTex->textureView(true));
336 descriptorResources.push_back(srcTex->resource());
337
338 cmdBuffer->bindDescriptorSets(gpu,
339 descriptorRecycledResources,
340 descriptorResources,
341 fPipelineLayout,
342 0,
343 2,
344 vkDescSets,
345 0,
346 nullptr);
347
348 // Set Dynamic viewport and stencil
349 // We always use one viewport the size of the RT
350 VkViewport viewport;
351 viewport.x = 0.0f;
352 viewport.y = 0.0f;
353 viewport.width = SkIntToScalar(rt->width());
354 viewport.height = SkIntToScalar(rt->height());
355 viewport.minDepth = 0.0f;
356 viewport.maxDepth = 1.0f;
357 cmdBuffer->setViewport(gpu, 0, 1, &viewport);
358
359 // We assume the scissor is not enabled so just set it to the whole RT
360 VkRect2D scissor;
361 scissor.extent.width = rt->width();
362 scissor.extent.height = rt->height();
363 scissor.offset.x = 0;
364 scissor.offset.y = 0;
365 cmdBuffer->setScissor(gpu, 0, 1, &scissor);
366
Hal Canary144caf52016-11-07 17:57:18 -0500367 cmdBuffer->bindVertexBuffer(gpu, fVertexBuffer.get());
egdanielbc9b2962016-09-27 08:00:53 -0700368 cmdBuffer->draw(gpu, 4, 1, 0, 0);
369 cmdBuffer->endRenderPass(gpu);
370
371 // Release all temp resources which should now be reffed by the cmd buffer
372 pipeline->unref(gpu);
373 uniformDS->unref(gpu);
374 samplerDS->unref(gpu);
375 sampler->unref(gpu);
376 renderPass->unref(gpu);
377
378 return true;
379}
380
381void GrVkCopyManager::destroyResources(GrVkGpu* gpu) {
382 if (VK_NULL_HANDLE != fVertShaderModule) {
383 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fVertShaderModule,
384 nullptr));
385 fVertShaderModule = VK_NULL_HANDLE;
386 }
387
388 if (VK_NULL_HANDLE != fFragShaderModule) {
389 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fFragShaderModule,
390 nullptr));
391 fFragShaderModule = VK_NULL_HANDLE;
392 }
393
394 if (VK_NULL_HANDLE != fPipelineLayout) {
395 GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(), fPipelineLayout,
396 nullptr));
397 fPipelineLayout = VK_NULL_HANDLE;
398 }
399
400 if (fUniformBuffer) {
401 fUniformBuffer->release(gpu);
Greg Danielf9f27232017-01-06 14:40:08 -0500402 fUniformBuffer.reset();
egdanielbc9b2962016-09-27 08:00:53 -0700403 }
404}
405
406void GrVkCopyManager::abandonResources() {
407 fVertShaderModule = VK_NULL_HANDLE;
408 fFragShaderModule = VK_NULL_HANDLE;
409 fPipelineLayout = VK_NULL_HANDLE;
410
411 if (fUniformBuffer) {
412 fUniformBuffer->abandon();
Greg Danielf9f27232017-01-06 14:40:08 -0500413 fUniformBuffer.reset();
egdanielbc9b2962016-09-27 08:00:53 -0700414 }
415}