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