Home | History | Annotate | Download | only in vk
      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