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 "GrRenderTargetPriv.h" 11 #include "GrSamplerState.h" 12 #include "GrShaderCaps.h" 13 #include "GrSurface.h" 14 #include "GrTexturePriv.h" 15 #include "GrVkCommandBuffer.h" 16 #include "GrVkCommandPool.h" 17 #include "GrVkCopyPipeline.h" 18 #include "GrVkDescriptorSet.h" 19 #include "GrVkGpu.h" 20 #include "GrVkImageView.h" 21 #include "GrVkPipelineLayout.h" 22 #include "GrVkRenderTarget.h" 23 #include "GrVkResourceProvider.h" 24 #include "GrVkSampler.h" 25 #include "GrVkTexture.h" 26 #include "GrVkUniformBuffer.h" 27 #include "GrVkVertexBuffer.h" 28 #include "SkPoint.h" 29 #include "SkRect.h" 30 #include "SkTraceEvent.h" 31 32 GrVkCopyManager::GrVkCopyManager() 33 : fVertShaderModule(VK_NULL_HANDLE) 34 , fFragShaderModule(VK_NULL_HANDLE) 35 , fPipelineLayout(nullptr) {} 36 37 GrVkCopyManager::~GrVkCopyManager() {} 38 39 bool GrVkCopyManager::createCopyProgram(GrVkGpu* gpu) { 40 TRACE_EVENT0("skia", TRACE_FUNC); 41 42 const GrShaderCaps* shaderCaps = gpu->caps()->shaderCaps(); 43 const char* version = shaderCaps->versionDeclString(); 44 SkString vertShaderText(version); 45 vertShaderText.append( 46 "#extension GL_ARB_separate_shader_objects : enable\n" 47 "#extension GL_ARB_shading_language_420pack : enable\n" 48 49 "layout(set = 0, binding = 0) uniform vertexUniformBuffer {" 50 "half4 uPosXform;" 51 "half4 uTexCoordXform;" 52 "};" 53 "layout(location = 0) in float2 inPosition;" 54 "layout(location = 1) out half2 vTexCoord;" 55 56 "// Copy Program VS\n" 57 "void main() {" 58 "vTexCoord = half2(inPosition * uTexCoordXform.xy + uTexCoordXform.zw);" 59 "sk_Position.xy = inPosition * uPosXform.xy + uPosXform.zw;" 60 "sk_Position.zw = half2(0, 1);" 61 "}" 62 ); 63 64 SkString fragShaderText(version); 65 fragShaderText.append( 66 "#extension GL_ARB_separate_shader_objects : enable\n" 67 "#extension GL_ARB_shading_language_420pack : enable\n" 68 69 "layout(set = 1, binding = 0) uniform sampler2D uTextureSampler;" 70 "layout(location = 1) in half2 vTexCoord;" 71 72 "// Copy Program FS\n" 73 "void main() {" 74 "sk_FragColor = texture(uTextureSampler, vTexCoord);" 75 "}" 76 ); 77 78 SkSL::Program::Settings settings; 79 SkSL::String spirv; 80 SkSL::Program::Inputs inputs; 81 if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(), VK_SHADER_STAGE_VERTEX_BIT, 82 &fVertShaderModule, &fShaderStageInfo[0], settings, &spirv, 83 &inputs)) { 84 this->destroyResources(gpu); 85 return false; 86 } 87 SkASSERT(inputs.isEmpty()); 88 89 if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT, 90 &fFragShaderModule, &fShaderStageInfo[1], settings, &spirv, 91 &inputs)) { 92 this->destroyResources(gpu); 93 return false; 94 } 95 SkASSERT(inputs.isEmpty()); 96 97 VkDescriptorSetLayout dsLayout[2]; 98 99 GrVkResourceProvider& resourceProvider = gpu->resourceProvider(); 100 101 dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout(); 102 103 uint32_t samplerVisibility = kFragment_GrShaderFlag; 104 SkTArray<uint32_t> visibilityArray(&samplerVisibility, 1); 105 106 resourceProvider.getSamplerDescriptorSetHandle(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 107 visibilityArray, &fSamplerDSHandle); 108 dsLayout[GrVkUniformHandler::kSamplerDescSet] = 109 resourceProvider.getSamplerDSLayout(fSamplerDSHandle); 110 111 // Create the VkPipelineLayout 112 VkPipelineLayoutCreateInfo layoutCreateInfo; 113 memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags)); 114 layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 115 layoutCreateInfo.pNext = 0; 116 layoutCreateInfo.flags = 0; 117 layoutCreateInfo.setLayoutCount = 2; 118 layoutCreateInfo.pSetLayouts = dsLayout; 119 layoutCreateInfo.pushConstantRangeCount = 0; 120 layoutCreateInfo.pPushConstantRanges = nullptr; 121 122 VkPipelineLayout pipelineLayout; 123 VkResult err = GR_VK_CALL(gpu->vkInterface(), CreatePipelineLayout(gpu->device(), 124 &layoutCreateInfo, 125 nullptr, 126 &pipelineLayout)); 127 if (err) { 128 this->destroyResources(gpu); 129 return false; 130 } 131 132 fPipelineLayout = new GrVkPipelineLayout(pipelineLayout); 133 134 static const float vdata[] = { 135 0, 0, 136 0, 1, 137 1, 0, 138 1, 1 139 }; 140 fVertexBuffer = GrVkVertexBuffer::Make(gpu, sizeof(vdata), false); 141 SkASSERT(fVertexBuffer.get()); 142 fVertexBuffer->updateData(vdata, sizeof(vdata)); 143 144 // We use 2 float4's for uniforms 145 fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, 8 * sizeof(float))); 146 SkASSERT(fUniformBuffer.get()); 147 148 return true; 149 } 150 151 bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu, 152 GrSurface* dst, GrSurfaceOrigin dstOrigin, 153 GrSurface* src, GrSurfaceOrigin srcOrigin, 154 const SkIRect& srcRect, const SkIPoint& dstPoint, 155 bool canDiscardOutsideDstRect) { 156 // None of our copy methods can handle a swizzle. TODO: Make copySurfaceAsDraw handle the 157 // swizzle. 158 if (gpu->caps()->shaderCaps()->configOutputSwizzle(src->config()) != 159 gpu->caps()->shaderCaps()->configOutputSwizzle(dst->config())) { 160 return false; 161 } 162 163 GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(dst->asRenderTarget()); 164 if (!rt) { 165 return false; 166 } 167 168 GrVkTexture* srcTex = static_cast<GrVkTexture*>(src->asTexture()); 169 if (!srcTex) { 170 return false; 171 } 172 173 if (VK_NULL_HANDLE == fVertShaderModule) { 174 SkASSERT(VK_NULL_HANDLE == fFragShaderModule && 175 nullptr == fPipelineLayout && 176 nullptr == fVertexBuffer.get() && 177 nullptr == fUniformBuffer.get()); 178 if (!this->createCopyProgram(gpu)) { 179 SkDebugf("Failed to create copy program.\n"); 180 return false; 181 } 182 } 183 SkASSERT(fPipelineLayout); 184 185 GrVkResourceProvider& resourceProv = gpu->resourceProvider(); 186 187 GrVkCopyPipeline* pipeline = resourceProv.findOrCreateCopyPipeline(rt, 188 fShaderStageInfo, 189 fPipelineLayout->layout()); 190 if (!pipeline) { 191 return false; 192 } 193 194 // UPDATE UNIFORM DESCRIPTOR SET 195 int w = srcRect.width(); 196 int h = srcRect.height(); 197 198 // dst rect edges in NDC (-1 to 1) 199 int dw = dst->width(); 200 int dh = dst->height(); 201 float dx0 = 2.f * dstPoint.fX / dw - 1.f; 202 float dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f; 203 float dy0 = 2.f * dstPoint.fY / dh - 1.f; 204 float dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f; 205 if (kBottomLeft_GrSurfaceOrigin == dstOrigin) { 206 dy0 = -dy0; 207 dy1 = -dy1; 208 } 209 210 211 float sx0 = (float)srcRect.fLeft; 212 float sx1 = (float)(srcRect.fLeft + w); 213 float sy0 = (float)srcRect.fTop; 214 float sy1 = (float)(srcRect.fTop + h); 215 int sh = src->height(); 216 if (kBottomLeft_GrSurfaceOrigin == srcOrigin) { 217 sy0 = sh - sy0; 218 sy1 = sh - sy1; 219 } 220 // src rect edges in normalized texture space (0 to 1). 221 int sw = src->width(); 222 sx0 /= sw; 223 sx1 /= sw; 224 sy0 /= sh; 225 sy1 /= sh; 226 227 float uniData[] = { dx1 - dx0, dy1 - dy0, dx0, dy0, // posXform 228 sx1 - sx0, sy1 - sy0, sx0, sy0 }; // texCoordXform 229 230 fUniformBuffer->updateData(gpu, uniData, sizeof(uniData), nullptr); 231 232 const GrVkDescriptorSet* uniformDS = resourceProv.getUniformDescriptorSet(); 233 SkASSERT(uniformDS); 234 235 VkDescriptorBufferInfo uniBufferInfo; 236 uniBufferInfo.buffer = fUniformBuffer->buffer(); 237 uniBufferInfo.offset = fUniformBuffer->offset(); 238 uniBufferInfo.range = fUniformBuffer->size(); 239 240 VkWriteDescriptorSet descriptorWrites; 241 descriptorWrites.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 242 descriptorWrites.pNext = nullptr; 243 descriptorWrites.dstSet = uniformDS->descriptorSet(); 244 descriptorWrites.dstBinding = GrVkUniformHandler::kGeometryBinding; 245 descriptorWrites.dstArrayElement = 0; 246 descriptorWrites.descriptorCount = 1; 247 descriptorWrites.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 248 descriptorWrites.pImageInfo = nullptr; 249 descriptorWrites.pBufferInfo = &uniBufferInfo; 250 descriptorWrites.pTexelBufferView = nullptr; 251 252 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(), 253 1, 254 &descriptorWrites, 255 0, nullptr)); 256 257 // UPDATE SAMPLER DESCRIPTOR SET 258 const GrVkDescriptorSet* samplerDS = 259 gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle); 260 261 GrSamplerState samplerState = GrSamplerState::ClampNearest(); 262 263 GrVkSampler* sampler = resourceProv.findOrCreateCompatibleSampler( 264 samplerState, GrVkYcbcrConversionInfo()); 265 266 VkDescriptorImageInfo imageInfo; 267 memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo)); 268 imageInfo.sampler = sampler->sampler(); 269 imageInfo.imageView = srcTex->textureView()->imageView(); 270 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 271 272 VkWriteDescriptorSet writeInfo; 273 memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet)); 274 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 275 writeInfo.pNext = nullptr; 276 writeInfo.dstSet = samplerDS->descriptorSet(); 277 writeInfo.dstBinding = 0; 278 writeInfo.dstArrayElement = 0; 279 writeInfo.descriptorCount = 1; 280 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 281 writeInfo.pImageInfo = &imageInfo; 282 writeInfo.pBufferInfo = nullptr; 283 writeInfo.pTexelBufferView = nullptr; 284 285 GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(), 286 1, 287 &writeInfo, 288 0, nullptr)); 289 290 VkDescriptorSet vkDescSets[] = { uniformDS->descriptorSet(), samplerDS->descriptorSet() }; 291 292 GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(srcTex->asRenderTarget()); 293 if (texRT) { 294 gpu->resolveRenderTargetNoFlush(texRT); 295 } 296 297 // TODO: Make tighter bounds and then adjust bounds for origin and granularity if we see 298 // any perf issues with using the whole bounds 299 SkIRect bounds = SkIRect::MakeWH(rt->width(), rt->height()); 300 301 // Change layouts of rt and texture. We aren't blending so we don't need color attachment read 302 // access for blending. 303 GrVkImage* targetImage = rt->msaaImage() ? rt->msaaImage() : rt; 304 VkAccessFlags dstAccessFlags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 305 if (!canDiscardOutsideDstRect) { 306 // We need to load the color attachment so need to be able to read it. 307 dstAccessFlags |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; 308 } 309 targetImage->setImageLayout(gpu, 310 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 311 dstAccessFlags, 312 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 313 false); 314 315 srcTex->setImageLayout(gpu, 316 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 317 VK_ACCESS_SHADER_READ_BIT, 318 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 319 false); 320 321 GrStencilAttachment* stencil = rt->renderTargetPriv().getStencilAttachment(); 322 if (stencil) { 323 GrVkStencilAttachment* vkStencil = (GrVkStencilAttachment*)stencil; 324 // We aren't actually using the stencil but we still load and store it so we need 325 // appropriate barriers. 326 // TODO: Once we refactor surface and how we conntect stencil to RTs, we should not even 327 // have the stencil on this render pass if possible. 328 vkStencil->setImageLayout(gpu, 329 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 330 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | 331 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, 332 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, 333 false); 334 } 335 336 VkAttachmentLoadOp loadOp = canDiscardOutsideDstRect ? VK_ATTACHMENT_LOAD_OP_DONT_CARE 337 : VK_ATTACHMENT_LOAD_OP_LOAD; 338 GrVkRenderPass::LoadStoreOps vkColorOps(loadOp, VK_ATTACHMENT_STORE_OP_STORE); 339 GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD, 340 VK_ATTACHMENT_STORE_OP_STORE); 341 const GrVkRenderPass* renderPass; 342 const GrVkResourceProvider::CompatibleRPHandle& rpHandle = rt->compatibleRenderPassHandle(); 343 if (rpHandle.isValid()) { 344 renderPass = gpu->resourceProvider().findRenderPass(rpHandle, 345 vkColorOps, 346 vkStencilOps); 347 } else { 348 renderPass = gpu->resourceProvider().findRenderPass(*rt, 349 vkColorOps, 350 vkStencilOps); 351 } 352 353 SkASSERT(renderPass->isCompatible(*rt->simpleRenderPass())); 354 355 GrVkPrimaryCommandBuffer* cmdBuffer = gpu->currentCommandBuffer(); 356 cmdBuffer->beginRenderPass(gpu, renderPass, nullptr, *rt, bounds, true); 357 358 GrVkSecondaryCommandBuffer* secondary = gpu->cmdPool()->findOrCreateSecondaryCommandBuffer(gpu); 359 if (!secondary) { 360 return false; 361 } 362 secondary->begin(gpu, rt->framebuffer(), renderPass); 363 364 secondary->bindPipeline(gpu, pipeline); 365 366 // Uniform DescriptorSet, Sampler DescriptorSet, and vertex shader uniformBuffer 367 SkSTArray<3, const GrVkRecycledResource*> descriptorRecycledResources; 368 descriptorRecycledResources.push_back(uniformDS); 369 descriptorRecycledResources.push_back(samplerDS); 370 descriptorRecycledResources.push_back(fUniformBuffer->resource()); 371 372 // One sampler, texture view, and texture 373 SkSTArray<3, const GrVkResource*> descriptorResources; 374 descriptorResources.push_back(sampler); 375 descriptorResources.push_back(srcTex->textureView()); 376 descriptorResources.push_back(srcTex->resource()); 377 378 secondary->bindDescriptorSets(gpu, 379 descriptorRecycledResources, 380 descriptorResources, 381 fPipelineLayout, 382 0, 383 2, 384 vkDescSets, 385 0, 386 nullptr); 387 388 // Set Dynamic viewport and stencil 389 // We always use one viewport the size of the RT 390 VkViewport viewport; 391 viewport.x = 0.0f; 392 viewport.y = 0.0f; 393 viewport.width = SkIntToScalar(rt->width()); 394 viewport.height = SkIntToScalar(rt->height()); 395 viewport.minDepth = 0.0f; 396 viewport.maxDepth = 1.0f; 397 secondary->setViewport(gpu, 0, 1, &viewport); 398 399 // We assume the scissor is not enabled so just set it to the whole RT 400 VkRect2D scissor; 401 scissor.extent.width = rt->width(); 402 scissor.extent.height = rt->height(); 403 scissor.offset.x = 0; 404 scissor.offset.y = 0; 405 secondary->setScissor(gpu, 0, 1, &scissor); 406 407 secondary->bindInputBuffer(gpu, 0, fVertexBuffer.get()); 408 secondary->draw(gpu, 4, 1, 0, 0); 409 secondary->end(gpu); 410 cmdBuffer->executeCommands(gpu, secondary); 411 cmdBuffer->endRenderPass(gpu); 412 secondary->unref(gpu); 413 414 // Release all temp resources which should now be reffed by the cmd buffer 415 pipeline->unref(gpu); 416 uniformDS->unref(gpu); 417 samplerDS->unref(gpu); 418 sampler->unref(gpu); 419 renderPass->unref(gpu); 420 421 return true; 422 } 423 424 void GrVkCopyManager::destroyResources(GrVkGpu* gpu) { 425 if (VK_NULL_HANDLE != fVertShaderModule) { 426 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fVertShaderModule, 427 nullptr)); 428 fVertShaderModule = VK_NULL_HANDLE; 429 } 430 431 if (VK_NULL_HANDLE != fFragShaderModule) { 432 GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fFragShaderModule, 433 nullptr)); 434 fFragShaderModule = VK_NULL_HANDLE; 435 } 436 437 if (fPipelineLayout) { 438 fPipelineLayout->unref(gpu); 439 fPipelineLayout = nullptr; 440 } 441 442 if (fUniformBuffer) { 443 fUniformBuffer->release(gpu); 444 fUniformBuffer.reset(); 445 } 446 } 447 448 void GrVkCopyManager::abandonResources() { 449 fVertShaderModule = VK_NULL_HANDLE; 450 fFragShaderModule = VK_NULL_HANDLE; 451 if (fPipelineLayout) { 452 fPipelineLayout->unrefAndAbandon(); 453 fPipelineLayout = nullptr; 454 } 455 456 if (fUniformBuffer) { 457 fUniformBuffer->abandon(); 458 fUniformBuffer.reset(); 459 } 460 } 461