| Index: src/gpu/vk/GrVkProgram.cpp
|
| diff --git a/src/gpu/vk/GrVkProgram.cpp b/src/gpu/vk/GrVkProgram.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7cccc7c46db85e7701aec2ea4e320b73ae0b502b
|
| --- /dev/null
|
| +++ b/src/gpu/vk/GrVkProgram.cpp
|
| @@ -0,0 +1,367 @@
|
| +/*
|
| +* Copyright 2016 Google Inc.
|
| +*
|
| +* Use of this source code is governed by a BSD-style license that can be
|
| +* found in the LICENSE file.
|
| +*/
|
| +
|
| +#include "GrVkProgram.h"
|
| +
|
| +#include "GrPipeline.h"
|
| +#include "GrVkCommandBuffer.h"
|
| +#include "GrVkDescriptorPool.h"
|
| +#include "GrVkGpu.h"
|
| +#include "GrVkImageView.h"
|
| +#include "GrVkMemory.h"
|
| +#include "GrVkPipeline.h"
|
| +#include "GrVkSampler.h"
|
| +#include "GrVkTexture.h"
|
| +#include "GrVkUniformBuffer.h"
|
| +#include "glsl/GrGLSLFragmentProcessor.h"
|
| +#include "glsl/GrGLSLGeometryProcessor.h"
|
| +#include "glsl/GrGLSLXferProcessor.h"
|
| +
|
| +GrVkProgram::GrVkProgram(GrVkGpu* gpu,
|
| + GrVkPipeline* pipeline,
|
| + VkPipelineLayout layout,
|
| + VkDescriptorSetLayout dsLayout[2],
|
| + GrVkDescriptorPool* descriptorPool,
|
| + VkDescriptorSet descriptorSets[2],
|
| + const BuiltinUniformHandles& builtinUniformHandles,
|
| + const UniformInfoArray& uniforms,
|
| + uint32_t vertexUniformSize,
|
| + uint32_t fragmentUniformSize,
|
| + uint32_t numSamplers,
|
| + GrGLSLPrimitiveProcessor* geometryProcessor,
|
| + GrGLSLXferProcessor* xferProcessor,
|
| + const GrGLSLFragProcs& fragmentProcessors)
|
| + : fDescriptorPool(descriptorPool)
|
| + , fPipeline(pipeline)
|
| + , fPipelineLayout(layout)
|
| + , fBuiltinUniformHandles(builtinUniformHandles)
|
| + , fGeometryProcessor(geometryProcessor)
|
| + , fXferProcessor(xferProcessor)
|
| + , fFragmentProcessors(fragmentProcessors)
|
| + , fProgramDataManager(uniforms, vertexUniformSize, fragmentUniformSize) {
|
| + fSamplers.setReserve(numSamplers);
|
| + fTextureViews.setReserve(numSamplers);
|
| + fTextures.setReserve(numSamplers);
|
| +
|
| + memcpy(fDSLayout, dsLayout, 2 * sizeof(VkDescriptorSetLayout));
|
| + memcpy(fDescriptorSets, descriptorSets, 2 * sizeof(VkDescriptorSetLayout));
|
| +
|
| + fVertexUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, vertexUniformSize, true));
|
| + fFragmentUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, fragmentUniformSize, true));
|
| +
|
| +#ifdef SK_DEBUG
|
| + fNumSamplers = numSamplers;
|
| +#endif
|
| +}
|
| +
|
| +GrVkProgram::~GrVkProgram() {
|
| + // Must of freed all GPU resources before this is destroyed
|
| + SkASSERT(!fPipeline);
|
| + SkASSERT(!fDescriptorPool);
|
| + SkASSERT(!fPipelineLayout);
|
| + SkASSERT(!fDSLayout[0]);
|
| + SkASSERT(!fDSLayout[1]);
|
| + SkASSERT(!fSamplers.count());
|
| + SkASSERT(!fTextureViews.count());
|
| + SkASSERT(!fTextures.count());
|
| +}
|
| +
|
| +void GrVkProgram::freeTempResources(const GrVkGpu* gpu) {
|
| + for (int i = 0; i < fSamplers.count(); ++i) {
|
| + fSamplers[i]->unref(gpu);
|
| + }
|
| + fSamplers.rewind();
|
| +
|
| + for (int i = 0; i < fTextureViews.count(); ++i) {
|
| + fTextureViews[i]->unref(gpu);
|
| + }
|
| + fTextureViews.rewind();
|
| +
|
| + for (int i = 0; i < fTextures.count(); ++i) {
|
| + fTextures[i]->unref(gpu);
|
| + }
|
| + fTextures.rewind();
|
| +}
|
| +
|
| +void GrVkProgram::freeGPUResources(const GrVkGpu* gpu) {
|
| + if (fPipeline) {
|
| + fPipeline->unref(gpu);
|
| + fPipeline = nullptr;
|
| + }
|
| + if (fDescriptorPool) {
|
| + fDescriptorPool->unref(gpu);
|
| + fDescriptorPool = nullptr;
|
| + }
|
| + if (fPipelineLayout) {
|
| + GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(),
|
| + fPipelineLayout,
|
| + nullptr));
|
| + fPipelineLayout = nullptr;
|
| + }
|
| +
|
| + if (fDSLayout[0]) {
|
| + GR_VK_CALL(gpu->vkInterface(), DestroyDescriptorSetLayout(gpu->device(), fDSLayout[0],
|
| + nullptr));
|
| + fDSLayout[0] = nullptr;
|
| + }
|
| + if (fDSLayout[1]) {
|
| + GR_VK_CALL(gpu->vkInterface(), DestroyDescriptorSetLayout(gpu->device(), fDSLayout[1],
|
| + nullptr));
|
| + fDSLayout[1] = nullptr;
|
| + }
|
| +
|
| + if (fVertexUniformBuffer) {
|
| + fVertexUniformBuffer->release(gpu);
|
| + }
|
| +
|
| + if (fFragmentUniformBuffer) {
|
| + fFragmentUniformBuffer->release(gpu);
|
| + }
|
| + this->freeTempResources(gpu);
|
| +}
|
| +
|
| +void GrVkProgram::abandonGPUResources() {
|
| + fPipeline->unrefAndAbandon();
|
| + fPipeline = nullptr;
|
| + fDescriptorPool->unrefAndAbandon();
|
| + fDescriptorPool = nullptr;
|
| + fPipelineLayout = nullptr;
|
| + fDSLayout[0] = nullptr;
|
| + fDSLayout[1] = nullptr;
|
| +
|
| + fVertexUniformBuffer->abandon();
|
| + fFragmentUniformBuffer->abandon();
|
| +
|
| + for (int i = 0; i < fSamplers.count(); ++i) {
|
| + fSamplers[i]->unrefAndAbandon();
|
| + }
|
| + fSamplers.rewind();
|
| +
|
| + for (int i = 0; i < fTextureViews.count(); ++i) {
|
| + fTextureViews[i]->unrefAndAbandon();
|
| + }
|
| + fTextureViews.rewind();
|
| +
|
| + for (int i = 0; i < fTextures.count(); ++i) {
|
| + fTextures[i]->unrefAndAbandon();
|
| + }
|
| + fTextures.rewind();
|
| +}
|
| +
|
| +static void append_texture_bindings(const GrProcessor& processor,
|
| + SkTArray<const GrTextureAccess*>* textureBindings) {
|
| + if (int numTextures = processor.numTextures()) {
|
| + const GrTextureAccess** bindings = textureBindings->push_back_n(numTextures);
|
| + int i = 0;
|
| + do {
|
| + bindings[i] = &processor.textureAccess(i);
|
| + } while (++i < numTextures);
|
| + }
|
| +}
|
| +
|
| +void GrVkProgram::setData(const GrVkGpu* gpu,
|
| + const GrPrimitiveProcessor& primProc,
|
| + const GrPipeline& pipeline) {
|
| + // This is here to protect against someone calling setData multiple times in a row without
|
| + // freeing the tempData between calls.
|
| + this->freeTempResources(gpu);
|
| +
|
| + this->setRenderTargetState(pipeline);
|
| +
|
| + SkSTArray<8, const GrTextureAccess*> textureBindings;
|
| +
|
| + fGeometryProcessor->setData(fProgramDataManager, primProc);
|
| + append_texture_bindings(primProc, &textureBindings);
|
| +
|
| + for (int i = 0; i < fFragmentProcessors.count(); ++i) {
|
| + const GrFragmentProcessor& processor = pipeline.getFragmentProcessor(i);
|
| + fFragmentProcessors[i]->setData(fProgramDataManager, processor);
|
| + fGeometryProcessor->setTransformData(primProc, fProgramDataManager, i,
|
| + processor.coordTransforms());
|
| + append_texture_bindings(processor, &textureBindings);
|
| + }
|
| +
|
| + fXferProcessor->setData(fProgramDataManager, pipeline.getXferProcessor());
|
| + append_texture_bindings(pipeline.getXferProcessor(), &textureBindings);
|
| +
|
| + this->writeUniformBuffers(gpu);
|
| +
|
| + this->writeSamplers(gpu, textureBindings);
|
| +}
|
| +
|
| +void GrVkProgram::writeUniformBuffers(const GrVkGpu* gpu) {
|
| + fProgramDataManager.uploadUniformBuffers(gpu, fVertexUniformBuffer, fFragmentUniformBuffer);
|
| +
|
| + VkWriteDescriptorSet descriptorWrites[2];
|
| + memset(descriptorWrites, 0, 2 * sizeof(VkWriteDescriptorSet));
|
| +
|
| + uint32_t firstUniformWrite = 0;
|
| + uint32_t uniformBindingUpdateCount = 0;
|
| +
|
| + // Vertex Uniform Buffer
|
| + if (fVertexUniformBuffer.get()) {
|
| + ++uniformBindingUpdateCount;
|
| + VkDescriptorBufferInfo vertBufferInfo;
|
| + memset(&vertBufferInfo, 0, sizeof(VkDescriptorBufferInfo));
|
| + vertBufferInfo.buffer = fVertexUniformBuffer->buffer();
|
| + vertBufferInfo.offset = 0;
|
| + vertBufferInfo.range = fVertexUniformBuffer->size();
|
| +
|
| + descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
| + descriptorWrites[0].pNext = nullptr;
|
| + descriptorWrites[0].dstSet = fDescriptorSets[1];
|
| + descriptorWrites[0].dstBinding = GrVkUniformHandler::kVertexBinding;
|
| + descriptorWrites[0].dstArrayElement = 0;
|
| + descriptorWrites[0].descriptorCount = 1;
|
| + descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
| + descriptorWrites[0].pImageInfo = nullptr;
|
| + descriptorWrites[0].pBufferInfo = &vertBufferInfo;
|
| + descriptorWrites[0].pTexelBufferView = nullptr;
|
| + }
|
| +
|
| + // Fragment Uniform Buffer
|
| + if (fFragmentUniformBuffer.get()) {
|
| + if (0 == uniformBindingUpdateCount) {
|
| + firstUniformWrite = 1;
|
| + }
|
| + ++uniformBindingUpdateCount;
|
| + VkDescriptorBufferInfo fragBufferInfo;
|
| + memset(&fragBufferInfo, 0, sizeof(VkDescriptorBufferInfo));
|
| + fragBufferInfo.buffer = fFragmentUniformBuffer->buffer();
|
| + fragBufferInfo.offset = 0;
|
| + fragBufferInfo.range = fFragmentUniformBuffer->size();
|
| +
|
| + descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
| + descriptorWrites[1].pNext = nullptr;
|
| + descriptorWrites[1].dstSet = fDescriptorSets[1];
|
| + descriptorWrites[1].dstBinding = GrVkUniformHandler::kFragBinding;;
|
| + descriptorWrites[1].dstArrayElement = 0;
|
| + descriptorWrites[1].descriptorCount = 1;
|
| + descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
| + descriptorWrites[1].pImageInfo = nullptr;
|
| + descriptorWrites[1].pBufferInfo = &fragBufferInfo;
|
| + descriptorWrites[1].pTexelBufferView = nullptr;
|
| + }
|
| +
|
| + if (uniformBindingUpdateCount) {
|
| + GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
|
| + uniformBindingUpdateCount,
|
| + &descriptorWrites[firstUniformWrite],
|
| + 0, nullptr));
|
| + }
|
| +}
|
| +
|
| +void GrVkProgram::writeSamplers(const GrVkGpu* gpu,
|
| + const SkTArray<const GrTextureAccess*>& textureBindings) {
|
| + SkASSERT(fNumSamplers == textureBindings.count());
|
| +
|
| + for (int i = 0; i < textureBindings.count(); ++i) {
|
| + fSamplers.push(GrVkSampler::Create(gpu, *textureBindings[i]));
|
| +
|
| + GrVkTexture* texture = static_cast<GrVkTexture*>(textureBindings[i]->getTexture());
|
| +
|
| + const GrVkImage::Resource* textureResource = texture->resource();
|
| + textureResource->ref();
|
| + fTextures.push(textureResource);
|
| +
|
| + const GrVkImageView* textureView = texture->textureView();
|
| + textureView->ref();
|
| + fTextureViews.push(textureView);
|
| +
|
| + // Change texture layout so it can be read in shader
|
| + VkImageLayout layout = texture->currentLayout();
|
| + VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout);
|
| + VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
| + VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout);
|
| + VkAccessFlags dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
| + texture->setImageLayout(gpu,
|
| + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
| + srcAccessMask,
|
| + dstAccessMask,
|
| + srcStageMask,
|
| + dstStageMask,
|
| + false);
|
| +
|
| + VkDescriptorImageInfo imageInfo;
|
| + memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
|
| + imageInfo.sampler = fSamplers[i]->sampler();
|
| + imageInfo.imageView = texture->textureView()->imageView();
|
| + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
| +
|
| + VkWriteDescriptorSet writeInfo;
|
| + memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet));
|
| + writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
| + writeInfo.pNext = nullptr;
|
| + writeInfo.dstSet = fDescriptorSets[GrVkUniformHandler::kSamplerDescSet];
|
| + writeInfo.dstBinding = i;
|
| + writeInfo.dstArrayElement = 0;
|
| + writeInfo.descriptorCount = 1;
|
| + writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
| + writeInfo.pImageInfo = &imageInfo;
|
| + writeInfo.pBufferInfo = nullptr;
|
| + writeInfo.pTexelBufferView = nullptr;
|
| +
|
| + GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
|
| + 1,
|
| + &writeInfo,
|
| + 0,
|
| + nullptr));
|
| + }
|
| +}
|
| +
|
| +void GrVkProgram::setRenderTargetState(const GrPipeline& pipeline) {
|
| + // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
|
| + if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
|
| + fRenderTargetState.fRenderTargetSize.fHeight != pipeline.getRenderTarget()->height()) {
|
| + fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni,
|
| + SkIntToScalar(pipeline.getRenderTarget()->height()));
|
| + }
|
| +
|
| + // set RT adjustment
|
| + const GrRenderTarget* rt = pipeline.getRenderTarget();
|
| + SkISize size;
|
| + size.set(rt->width(), rt->height());
|
| + SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
|
| + if (fRenderTargetState.fRenderTargetOrigin != rt->origin() ||
|
| + fRenderTargetState.fRenderTargetSize != size) {
|
| + fRenderTargetState.fRenderTargetSize = size;
|
| + fRenderTargetState.fRenderTargetOrigin = rt->origin();
|
| +
|
| + float rtAdjustmentVec[4];
|
| + fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
|
| + fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
|
| + }
|
| +}
|
| +
|
| +void GrVkProgram::bind(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer) {
|
| + commandBuffer->bindPipeline(gpu, fPipeline);
|
| + commandBuffer->bindDescriptorSets(gpu, this, fPipelineLayout, 0, 2, fDescriptorSets, 0,
|
| + nullptr);
|
| +}
|
| +
|
| +void GrVkProgram::addUniformResources(GrVkCommandBuffer& commandBuffer) {
|
| +#if 1
|
| + commandBuffer.addResource(fDescriptorPool);
|
| + if (fVertexUniformBuffer.get()) {
|
| + commandBuffer.addResource(fVertexUniformBuffer->resource());
|
| + }
|
| + if (fFragmentUniformBuffer.get()) {
|
| + commandBuffer.addResource(fFragmentUniformBuffer->resource());
|
| + }
|
| + for (int i = 0; i < fSamplers.count(); ++i) {
|
| + commandBuffer.addResource(fSamplers[i]);
|
| + }
|
| +
|
| + for (int i = 0; i < fTextureViews.count(); ++i) {
|
| + commandBuffer.addResource(fTextureViews[i]);
|
| + }
|
| +
|
| + for (int i = 0; i < fTextures.count(); ++i) {
|
| + commandBuffer.addResource(fTextures[i]);
|
| + }
|
| +#endif
|
| +}
|
|
|