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