OLD | NEW |
---|---|
(Empty) | |
1 /* | |
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 | |
10 #include "GrSurface.h" | |
11 #include "GrTextureParams.h" | |
12 #include "GrTexturePriv.h" | |
13 #include "GrVkCommandBuffer.h" | |
14 #include "GrVkCopyPipeline.h" | |
15 #include "GrVkDescriptorSet.h" | |
16 #include "GrVkGpu.h" | |
17 #include "GrVkImageView.h" | |
18 #include "GrVkRenderTarget.h" | |
19 #include "GrVkResourceProvider.h" | |
20 #include "GrVkSampler.h" | |
21 #include "GrVkTexture.h" | |
22 #include "GrVkUniformBuffer.h" | |
23 #include "GrVkVertexBuffer.h" | |
24 #include "SkPoint.h" | |
25 #include "SkRect.h" | |
26 | |
27 bool GrVkCopyManager::createCopyProgram(GrVkGpu* gpu) { | |
28 const GrGLSLCaps* glslCaps = gpu->vkCaps().glslCaps(); | |
29 const char* version = glslCaps->versionDeclString(); | |
30 SkString vertShaderText(version); | |
31 vertShaderText.append( | |
32 "#extension GL_ARB_separate_shader_objects : enable\n" | |
33 "#extension GL_ARB_shading_language_420pack : enable\n" | |
34 | |
35 "layout(set = 0, binding = 0) uniform vertexUniformBuffer {" | |
36 "mediump vec4 uPosXform;" | |
37 "mediump vec4 uTexCoordXform;" | |
38 "};" | |
39 "layout(location = 0) in highp vec2 inPosition;" | |
40 "layout(location = 1) out mediump vec2 vTexCoord;" | |
41 | |
42 "// Copy Program VS\n" | |
43 "void main() {" | |
44 "vTexCoord = inPosition * uTexCoordXform.xy + uTexCoordXform.zw;" | |
Brian Osman
2016/09/25 19:58:48
nit: indentation
egdaniel
2016/09/26 15:16:49
Done.
| |
45 "gl_Position.xy = inPosition * uPosXform.xy + uPosXform.zw;" | |
46 "gl_Position.zw = vec2(0, 1);" | |
47 "}" | |
48 ); | |
49 | |
50 SkString fragShaderText(version); | |
51 fragShaderText.append( | |
52 "#extension GL_ARB_separate_shader_objects : enable\n" | |
53 "#extension GL_ARB_shading_language_420pack : enable\n" | |
54 | |
55 "precision mediump float;" | |
56 | |
57 "layout(set = 1, binding = 0) uniform mediump sampler2D uTextureSampler; " | |
58 "layout(location = 1) in mediump vec2 vTexCoord;" | |
59 "layout(location = 0, index = 0) out mediump vec4 fsColorOut;" | |
60 | |
61 "// Copy Program FS\n" | |
62 "void main() {" | |
63 "fsColorOut = texture(uTextureSampler, vTexCoord);" | |
64 "}" | |
65 ); | |
66 | |
67 if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(), | |
68 VK_SHADER_STAGE_VERTEX_BIT, | |
69 &fVertShaderModule, &fShaderStageInfo[0])) { | |
70 this->destroyResources(gpu); | |
71 return false; | |
72 } | |
73 | |
74 if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(), | |
75 VK_SHADER_STAGE_FRAGMENT_BIT, | |
76 &fFragShaderModule, &fShaderStageInfo[1])) { | |
77 this->destroyResources(gpu); | |
78 return false; | |
79 } | |
80 | |
81 VkDescriptorSetLayout dsLayout[2]; | |
82 | |
83 GrVkResourceProvider& resourceProvider = gpu->resourceProvider(); | |
84 | |
85 dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUn iformDSLayout(); | |
86 | |
87 uint32_t samplerVisibility = kFragment_GrShaderFlag; | |
88 SkTArray<uint32_t> visibilityArray(&samplerVisibility, 1); | |
89 | |
90 resourceProvider.getSamplerDescriptorSetHandle(visibilityArray, &fSamplerDSH andle); | |
91 dsLayout[GrVkUniformHandler::kSamplerDescSet] = | |
92 resourceProvider.getSamplerDSLayout(fSamplerDSHandle); | |
93 | |
94 // Create the VkPipelineLayout | |
95 VkPipelineLayoutCreateInfo layoutCreateInfo; | |
96 memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags)); | |
97 layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; | |
98 layoutCreateInfo.pNext = 0; | |
99 layoutCreateInfo.flags = 0; | |
100 layoutCreateInfo.setLayoutCount = 2; | |
101 layoutCreateInfo.pSetLayouts = dsLayout; | |
102 layoutCreateInfo.pushConstantRangeCount = 0; | |
103 layoutCreateInfo.pPushConstantRanges = nullptr; | |
104 | |
105 VkResult err = GR_VK_CALL(gpu->vkInterface(), CreatePipelineLayout(gpu->devi ce(), | |
106 &layoutCr eateInfo, | |
107 nullptr, | |
108 &fPipelin eLayout)); | |
109 if (err) { | |
110 this->destroyResources(gpu); | |
111 return false; | |
112 } | |
113 | |
114 static const float vdata[] = { | |
115 0, 0, | |
116 0, 1, | |
117 1, 0, | |
118 1, 1 | |
119 }; | |
120 fVertexBuffer.reset(GrVkVertexBuffer::Create(gpu, sizeof(vdata), false)); | |
121 SkASSERT(fVertexBuffer.get()); | |
122 fVertexBuffer->updateData(vdata, sizeof(vdata)); | |
123 | |
124 // We use 2 vec4's for uniforms | |
125 fUniformBuffer = GrVkUniformBuffer::Create(gpu, 8 * sizeof(float)); | |
126 SkASSERT(fUniformBuffer); | |
127 | |
128 return true; | |
129 } | |
130 | |
131 bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu, | |
132 GrSurface* dst, | |
133 GrSurface* src, | |
134 const SkIRect& srcRect, | |
135 const SkIPoint& dstPoint) { | |
136 if (!gpu->vkCaps().supportsCopiesAsDraws()) { | |
137 return false; | |
138 } | |
139 | |
140 GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(dst->asRenderTarget()) ; | |
141 if (!rt) { | |
142 return false; | |
143 } | |
144 | |
145 GrVkTexture* srcTex = static_cast<GrVkTexture*>(src->asTexture()); | |
146 if (!srcTex) { | |
147 return false; | |
148 } | |
149 | |
150 if (VK_NULL_HANDLE == fVertShaderModule) { | |
151 SkASSERT(VK_NULL_HANDLE == fFragShaderModule && | |
152 VK_NULL_HANDLE == fPipelineLayout && | |
153 nullptr == fVertexBuffer.get() && | |
154 nullptr == fUniformBuffer); | |
155 if (!this->createCopyProgram(gpu)) { | |
156 SkDebugf("Failed to create copy program.\n"); | |
157 return false; | |
158 } | |
159 } | |
160 | |
161 GrVkResourceProvider& resourceProv = gpu->resourceProvider(); | |
162 | |
163 GrVkCopyPipeline* pipeline = resourceProv.findOrCreateCopyPipeline(rt, | |
164 fShaderSt ageInfo, | |
165 fPipeline Layout); | |
166 if (!pipeline) { | |
167 return false; | |
168 } | |
169 | |
170 // UPDATE UNIFORM DESCRIPTOR SET | |
171 int w = srcRect.width(); | |
172 int h = srcRect.height(); | |
173 | |
174 // dst rect edges in NDC (-1 to 1) | |
175 int dw = dst->width(); | |
176 int dh = dst->height(); | |
177 float dx0 = 2.f * dstPoint.fX / dw - 1.f; | |
178 float dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f; | |
179 float dy0 = 2.f * dstPoint.fY / dh - 1.f; | |
180 float dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f; | |
181 if (kBottomLeft_GrSurfaceOrigin == dst->origin()) { | |
182 dy0 = -dy0; | |
183 dy1 = -dy1; | |
184 } | |
185 | |
186 | |
187 float sx0 = (float)srcRect.fLeft; | |
188 float sx1 = (float)(srcRect.fLeft + w); | |
189 float sy0 = (float)srcRect.fTop; | |
190 float sy1 = (float)(srcRect.fTop + h); | |
191 int sh = src->height(); | |
192 if (kBottomLeft_GrSurfaceOrigin == src->origin()) { | |
193 sy0 = sh - sy0; | |
194 sy1 = sh - sy1; | |
195 } | |
196 // src rect edges in normalized texture space (0 to 1). | |
197 int sw = src->width(); | |
198 sx0 /= sw; | |
199 sx1 /= sw; | |
200 sy0 /= sh; | |
201 sy1 /= sh; | |
202 | |
203 float uniData[] = { dx1 - dx0, dy1 - dy0, dx0, dy0, // posXform | |
204 sx1 - sx0, sy1 - sy0, sx0, sy0 }; // texCoordXform | |
205 | |
206 fUniformBuffer->updateData(gpu, uniData, sizeof(uniData), nullptr); | |
207 | |
208 const GrVkDescriptorSet* uniformDS = resourceProv.getUniformDescriptorSet(); | |
209 SkASSERT(uniformDS); | |
210 | |
211 VkDescriptorBufferInfo uniBufferInfo; | |
212 uniBufferInfo.buffer = fUniformBuffer->buffer(); | |
213 uniBufferInfo.offset = fUniformBuffer->offset(); | |
214 uniBufferInfo.range = fUniformBuffer->size(); | |
215 | |
216 VkWriteDescriptorSet descriptorWrites; | |
217 descriptorWrites.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; | |
218 descriptorWrites.pNext = nullptr; | |
219 descriptorWrites.dstSet = uniformDS->descriptorSet(); | |
220 descriptorWrites.dstBinding = GrVkUniformHandler::kVertexBinding; | |
221 descriptorWrites.dstArrayElement = 0; | |
222 descriptorWrites.descriptorCount = 1; | |
223 descriptorWrites.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; | |
224 descriptorWrites.pImageInfo = nullptr; | |
225 descriptorWrites.pBufferInfo = &uniBufferInfo; | |
226 descriptorWrites.pTexelBufferView = nullptr; | |
227 | |
228 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(), | |
229 1, | |
230 &descriptorWrites, | |
231 0, nullptr)); | |
232 | |
233 // UPDATE SAMPLER DESCRIPTOR SET | |
234 const GrVkDescriptorSet* samplerDS = | |
235 gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle); | |
236 | |
237 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_Fil terMode); | |
238 | |
239 GrVkSampler* sampler = | |
240 resourceProv.findOrCreateCompatibleSampler(params, srcTex->texturePriv() .maxMipMapLevel()); | |
241 | |
242 VkDescriptorImageInfo imageInfo; | |
243 memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo)); | |
244 imageInfo.sampler = sampler->sampler(); | |
245 imageInfo.imageView = srcTex->textureView(true)->imageView(); | |
246 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; | |
247 | |
248 VkWriteDescriptorSet writeInfo; | |
249 memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet)); | |
250 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; | |
251 writeInfo.pNext = nullptr; | |
252 writeInfo.dstSet = samplerDS->descriptorSet(); | |
253 writeInfo.dstBinding = 0; | |
254 writeInfo.dstArrayElement = 0; | |
255 writeInfo.descriptorCount = 1; | |
256 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; | |
257 writeInfo.pImageInfo = &imageInfo; | |
258 writeInfo.pBufferInfo = nullptr; | |
259 writeInfo.pTexelBufferView = nullptr; | |
260 | |
261 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(), | |
262 1, | |
263 &writeInfo, | |
264 0, nullptr)); | |
265 | |
266 VkDescriptorSet vkDescSets[] = { uniformDS->descriptorSet(), samplerDS->desc riptorSet() }; | |
267 | |
268 GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(srcTex->asRenderTar get()); | |
269 if (texRT) { | |
270 gpu->onResolveRenderTarget(texRT); | |
271 } | |
272 | |
273 GrVkPrimaryCommandBuffer* cmdBuffer = gpu->currentCommandBuffer(); | |
274 | |
275 // TODO: Make tighter bounds and then adjust bounds for origin and granulari ty if we see | |
276 // any perf issues with using the whole bounds | |
277 SkIRect bounds = SkIRect::MakeWH(rt->width(), rt->height()); | |
278 | |
279 // Change layouts of rt and texture | |
280 GrVkImage* targetImage = rt->msaaImage() ? rt->msaaImage() : rt; | |
281 targetImage->setImageLayout(gpu, | |
282 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, | |
283 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, | |
284 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, | |
285 false); | |
286 | |
287 srcTex->setImageLayout(gpu, | |
288 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, | |
289 VK_ACCESS_SHADER_READ_BIT, | |
290 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, | |
291 false); | |
292 | |
293 GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE, | |
294 VK_ATTACHMENT_STORE_OP_STORE); | |
295 GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE, | |
296 VK_ATTACHMENT_STORE_OP_STORE); | |
297 GrVkRenderPass::LoadStoreOps vkResolveOps(VK_ATTACHMENT_LOAD_OP_DONT_CARE, | |
298 VK_ATTACHMENT_STORE_OP_STORE); | |
299 const GrVkRenderPass* renderPass; | |
300 const GrVkResourceProvider::CompatibleRPHandle& rpHandle = | |
301 rt->compatibleRenderPassHandle(); | |
302 if (rpHandle.isValid()) { | |
303 renderPass = gpu->resourceProvider().findRenderPass(rpHandle, | |
304 vkColorOps, | |
Brian Osman
2016/09/25 19:58:48
nit: indentation
egdaniel
2016/09/26 15:16:49
Done.
| |
305 vkResolveOps, | |
306 vkStencilOps); | |
307 } else { | |
308 renderPass = gpu->resourceProvider().findRenderPass(*rt, | |
309 vkColorOps, | |
Brian Osman
2016/09/25 19:58:48
nit: indentation
egdaniel
2016/09/26 15:16:49
Done.
| |
310 vkResolveOps, | |
311 vkStencilOps); | |
312 } | |
313 | |
314 SkASSERT(renderPass->isCompatible(*rt->simpleRenderPass())); | |
315 | |
316 | |
317 cmdBuffer->beginRenderPass(gpu, renderPass, 0, nullptr, *rt, bounds, false); | |
318 cmdBuffer->bindPipeline(gpu, pipeline); | |
319 | |
320 // Uniform DescriptorSet, Sampler DescriptorSet, and vertex shader uniformBu ffer | |
321 SkSTArray<3, const GrVkRecycledResource*> descriptorRecycledResources; | |
322 descriptorRecycledResources.push_back(uniformDS); | |
323 descriptorRecycledResources.push_back(samplerDS); | |
324 descriptorRecycledResources.push_back(fUniformBuffer->resource()); | |
325 | |
326 // One sampler, texture view, and texture | |
327 SkSTArray<3, const GrVkResource*> descriptorResources; | |
328 descriptorResources.push_back(sampler); | |
329 descriptorResources.push_back(srcTex->textureView(true)); | |
330 descriptorResources.push_back(srcTex->resource()); | |
331 | |
332 cmdBuffer->bindDescriptorSets(gpu, | |
333 descriptorRecycledResources, | |
334 descriptorResources, | |
335 fPipelineLayout, | |
336 0, | |
337 2, | |
338 vkDescSets, | |
339 0, | |
340 nullptr); | |
341 | |
342 // Set Dynamic viewport and stencil | |
343 // We always use one viewport the size of the RT | |
344 VkViewport viewport; | |
345 viewport.x = 0.0f; | |
346 viewport.y = 0.0f; | |
347 viewport.width = SkIntToScalar(rt->width()); | |
348 viewport.height = SkIntToScalar(rt->height()); | |
349 viewport.minDepth = 0.0f; | |
350 viewport.maxDepth = 1.0f; | |
351 cmdBuffer->setViewport(gpu, 0, 1, &viewport); | |
352 | |
353 // We assume the scissor is not enabled so just set it to the whole RT | |
354 VkRect2D scissor; | |
355 scissor.extent.width = rt->width(); | |
356 scissor.extent.height = rt->height(); | |
357 scissor.offset.x = 0; | |
358 scissor.offset.y = 0; | |
359 cmdBuffer->setScissor(gpu, 0, 1, &scissor); | |
360 | |
361 cmdBuffer->bindVertexBuffer(gpu, fVertexBuffer); | |
362 cmdBuffer->draw(gpu, 4, 1, 0, 0); | |
363 cmdBuffer->endRenderPass(gpu); | |
364 | |
365 // Release all temp resources which should now be reffed by the cmd buffer | |
366 pipeline->unref(gpu); | |
367 uniformDS->unref(gpu); | |
368 samplerDS->unref(gpu); | |
369 sampler->unref(gpu); | |
370 renderPass->unref(gpu); | |
371 | |
372 return true; | |
373 } | |
374 | |
375 void GrVkCopyManager::destroyResources(GrVkGpu* gpu) { | |
376 if (VK_NULL_HANDLE != fVertShaderModule) { | |
377 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fVertS haderModule, | |
378 nullptr)); | |
379 fVertShaderModule = VK_NULL_HANDLE; | |
380 } | |
381 | |
382 if (VK_NULL_HANDLE != fFragShaderModule) { | |
383 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fFragS haderModule, | |
384 nullptr)); | |
385 fFragShaderModule = VK_NULL_HANDLE; | |
386 } | |
387 | |
388 if (VK_NULL_HANDLE != fPipelineLayout) { | |
389 GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(), fPip elineLayout, | |
390 nullptr)); | |
391 fPipelineLayout = VK_NULL_HANDLE; | |
392 } | |
393 | |
394 if (fUniformBuffer) { | |
395 fUniformBuffer->release(gpu); | |
396 fUniformBuffer = nullptr; | |
397 } | |
398 } | |
399 | |
400 void GrVkCopyManager::abandonResources() { | |
401 fVertShaderModule = VK_NULL_HANDLE; | |
402 fFragShaderModule = VK_NULL_HANDLE; | |
403 fPipelineLayout = VK_NULL_HANDLE; | |
404 | |
405 if (fUniformBuffer) { | |
406 fUniformBuffer->abandon(); | |
407 fUniformBuffer = nullptr; | |
408 } | |
409 } | |
OLD | NEW |