/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// This is a GPU-backend specific test. It relies on static intializers to work
#include "SkTypes.h"
#if SK_SUPPORT_GPU && defined(SK_VULKAN)
#include "GrContextFactory.h"
#include "GrContextPriv.h"
#include "GrTest.h"
#include "GrTexture.h"
#include "Test.h"
#include "vk/GrVkCopyPipeline.h"
#include "vk/GrVkGpu.h"
#include "vk/GrVkRenderTarget.h"
#include "vk/GrVkUtil.h"
using sk_gpu_test::GrContextFactory;
class TestVkCopyProgram {
public:
TestVkCopyProgram()
: fVertShaderModule(VK_NULL_HANDLE)
, fFragShaderModule(VK_NULL_HANDLE)
, fPipelineLayout(VK_NULL_HANDLE) {}
void test(GrVkGpu* gpu, skiatest::Reporter* reporter) {
const char vertShaderText[] =
"#extension GL_ARB_separate_shader_objects : enable\n"
"#extension GL_ARB_shading_language_420pack : enable\n"
"layout(set = 0, binding = 0) uniform vertexUniformBuffer {"
"half4 uPosXform;"
"half4 uTexCoordXform;"
"};"
"layout(location = 0) in float2 inPosition;"
"layout(location = 1) out half2 vTexCoord;"
"// Copy Program VS\n"
"void main() {"
"vTexCoord = inPosition * uTexCoordXform.xy + uTexCoordXform.zw;"
"sk_Position.xy = inPosition * uPosXform.xy + uPosXform.zw;"
"sk_Position.zw = half2(0, 1);"
"}";
const char fragShaderText[] =
"#extension GL_ARB_separate_shader_objects : enable\n"
"#extension GL_ARB_shading_language_420pack : enable\n"
"layout(set = 1, binding = 0) uniform sampler2D uTextureSampler;"
"layout(location = 1) in half2 vTexCoord;"
"layout(location = 0, index = 0) out half4 fsColorOut;"
"// Copy Program FS\n"
"void main() {"
"fsColorOut = texture(uTextureSampler, vTexCoord);"
"}";
SkSL::Program::Settings settings;
SkSL::Program::Inputs inputs;
if (!GrCompileVkShaderModule(gpu, vertShaderText, VK_SHADER_STAGE_VERTEX_BIT,
&fVertShaderModule, &fShaderStageInfo[0], settings, &inputs)) {
this->destroyResources(gpu);
REPORTER_ASSERT(reporter, false);
return;
}
SkASSERT(inputs.isEmpty());
if (!GrCompileVkShaderModule(gpu, fragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT,
&fFragShaderModule, &fShaderStageInfo[1], settings, &inputs)) {
this->destroyResources(gpu);
REPORTER_ASSERT(reporter, false);
return;
}
VkDescriptorSetLayout dsLayout[2];
GrVkResourceProvider& resourceProvider = gpu->resourceProvider();
dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout();
uint32_t samplerVisibility = kFragment_GrShaderFlag;
SkTArray<uint32_t> visibilityArray(&samplerVisibility, 1);
resourceProvider.getSamplerDescriptorSetHandle(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
visibilityArray, &fSamplerDSHandle);
dsLayout[GrVkUniformHandler::kSamplerDescSet] =
resourceProvider.getSamplerDSLayout(fSamplerDSHandle);
// Create the VkPipelineLayout
VkPipelineLayoutCreateInfo layoutCreateInfo;
memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags));
layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
layoutCreateInfo.pNext = 0;
layoutCreateInfo.flags = 0;
layoutCreateInfo.setLayoutCount = 2;
layoutCreateInfo.pSetLayouts = dsLayout;
layoutCreateInfo.pushConstantRangeCount = 0;
layoutCreateInfo.pPushConstantRanges = nullptr;
VkResult err = GR_VK_CALL(gpu->vkInterface(), CreatePipelineLayout(gpu->device(),
&layoutCreateInfo,
nullptr,
&fPipelineLayout));
if (err) {
this->destroyResources(gpu);
REPORTER_ASSERT(reporter, false);
return;
}
GrSurfaceDesc surfDesc;
surfDesc.fFlags = kRenderTarget_GrSurfaceFlag;
surfDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
surfDesc.fWidth = 16;
surfDesc.fHeight = 16;
surfDesc.fConfig = kRGBA_8888_GrPixelConfig;
surfDesc.fSampleCnt = 1;
sk_sp<GrTexture> tex = gpu->createTexture(surfDesc, SkBudgeted::kNo);
if (!tex) {
this->destroyResources(gpu);
REPORTER_ASSERT(reporter, tex.get());
return;
}
GrRenderTarget* rt = tex->asRenderTarget();
REPORTER_ASSERT(reporter, rt);
GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt);
GrVkCopyPipeline* copyPipeline = GrVkCopyPipeline::Create(gpu,
fShaderStageInfo,
fPipelineLayout,
1,
*vkRT->simpleRenderPass(),
VK_NULL_HANDLE);
REPORTER_ASSERT(reporter, copyPipeline);
if (copyPipeline) {
copyPipeline->unref(gpu);
}
this->destroyResources(gpu);
}
void destroyResources(GrVkGpu* gpu) {
if (VK_NULL_HANDLE != fVertShaderModule) {
GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fVertShaderModule,
nullptr));
fVertShaderModule = VK_NULL_HANDLE;
}
if (VK_NULL_HANDLE != fFragShaderModule) {
GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fFragShaderModule,
nullptr));
fFragShaderModule = VK_NULL_HANDLE;
}
if (VK_NULL_HANDLE != fPipelineLayout) {
GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(), fPipelineLayout,
nullptr));
fPipelineLayout = VK_NULL_HANDLE;
}
}
VkShaderModule fVertShaderModule;
VkShaderModule fFragShaderModule;
VkPipelineShaderStageCreateInfo fShaderStageInfo[2];
GrVkDescriptorSetManager::Handle fSamplerDSHandle;
VkPipelineLayout fPipelineLayout;
};
DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkMakeCopyPipelineTest, reporter, ctxInfo) {
GrContext* context = ctxInfo.grContext();
GrVkGpu* gpu = static_cast<GrVkGpu*>(context->contextPriv().getGpu());
if (!gpu->vkCaps().supportsCopiesAsDraws()) {
return;
}
TestVkCopyProgram copyProgram;
copyProgram.test(gpu, reporter);
}
#endif