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 "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