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;" |
| 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, |
| 305 vkResolveOps, |
| 306 vkStencilOps); |
| 307 } else { |
| 308 renderPass = gpu->resourceProvider().findRenderPass(*rt, |
| 309 vkColorOps, |
| 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 |