aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar jvanverth <jvanverth@google.com>2016-02-26 09:21:02 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-02-26 09:21:02 -0800
commit992ad363d7ca879cdb86f802b379f06800a44125 (patch)
tree7eb5d36f2d2f9bdc28f5321c61ad754b0ef30858 /src
parentfe4b4f00d759ef7ac135ea2d104971b7fad66cda (diff)
Add back Vk files with LF endings
Diffstat (limited to 'src')
-rw-r--r--src/gpu/vk/GrVkProgram.cpp367
-rw-r--r--src/gpu/vk/GrVkProgram.h161
-rw-r--r--src/gpu/vk/GrVkProgramBuilder.cpp323
-rw-r--r--src/gpu/vk/GrVkProgramDataManager.h70
-rw-r--r--src/gpu/vk/GrVkSampler.cpp74
-rw-r--r--src/gpu/vk/GrVkVaryingHandler.cpp26
6 files changed, 1021 insertions, 0 deletions
diff --git a/src/gpu/vk/GrVkProgram.cpp b/src/gpu/vk/GrVkProgram.cpp
new file mode 100644
index 0000000000..cec3eee6f3
--- /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
+}
diff --git a/src/gpu/vk/GrVkProgram.h b/src/gpu/vk/GrVkProgram.h
new file mode 100644
index 0000000000..e0477260e9
--- /dev/null
+++ b/src/gpu/vk/GrVkProgram.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrVkProgram_DEFINED
+#define GrVkProgram_DEFINED
+
+#include "GrVkImage.h"
+#include "GrVkProgramDesc.h"
+#include "GrVkProgramDataManager.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+
+#include "vulkan/vulkan.h"
+
+class GrPipeline;
+class GrVkCommandBuffer;
+class GrVkDescriptorPool;
+class GrVkGpu;
+class GrVkImageView;
+class GrVkPipeline;
+class GrVkSampler;
+class GrVkUniformBuffer;
+
+class GrVkProgram : public SkRefCnt {
+public:
+ typedef GrGLSLProgramBuilder::BuiltinUniformHandles BuiltinUniformHandles;
+
+ ~GrVkProgram();
+
+ GrVkPipeline* vkPipeline() const { return fPipeline; }
+
+ void setData(const GrVkGpu*, const GrPrimitiveProcessor&, const GrPipeline&);
+
+ void bind(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer);
+
+ void addUniformResources(GrVkCommandBuffer&);
+
+ void freeGPUResources(const GrVkGpu* gpu);
+
+ // This releases resources the only a given instance of a GrVkProgram needs to hold onto and do
+ // don't need to survive across new uses of the program.
+ void freeTempResources(const GrVkGpu* gpu);
+
+ void abandonGPUResources();
+
+private:
+ typedef GrVkProgramDataManager::UniformInfoArray UniformInfoArray;
+ typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
+
+ 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);
+
+ void writeUniformBuffers(const GrVkGpu* gpu);
+
+ void writeSamplers(const GrVkGpu* gpu, const SkTArray<const GrTextureAccess*>& textureBindings);
+
+
+ /**
+ * We use the RT's size and origin to adjust from Skia device space to OpenGL normalized device
+ * space and to make device space positions have the correct origin for processors that require
+ * them.
+ */
+ struct RenderTargetState {
+ SkISize fRenderTargetSize;
+ GrSurfaceOrigin fRenderTargetOrigin;
+
+ RenderTargetState() { this->invalidate(); }
+ void invalidate() {
+ fRenderTargetSize.fWidth = -1;
+ fRenderTargetSize.fHeight = -1;
+ fRenderTargetOrigin = (GrSurfaceOrigin)-1;
+ }
+
+ /**
+ * Gets a vec4 that adjusts the position from Skia device coords to GL's normalized device
+ * coords. Assuming the transformed position, pos, is a homogeneous vec3, the vec, v, is
+ * applied as such:
+ * pos.x = dot(v.xy, pos.xz)
+ * pos.y = dot(v.zw, pos.yz)
+ */
+ void getRTAdjustmentVec(float* destVec) {
+ destVec[0] = 2.f / fRenderTargetSize.fWidth;
+ destVec[1] = -1.f;
+ if (kBottomLeft_GrSurfaceOrigin == fRenderTargetOrigin) {
+ destVec[2] = -2.f / fRenderTargetSize.fHeight;
+ destVec[3] = 1.f;
+ } else {
+ destVec[2] = 2.f / fRenderTargetSize.fHeight;
+ destVec[3] = -1.f;
+ }
+ }
+ };
+
+ // Helper for setData() that sets the view matrix and loads the render target height uniform
+ void setRenderTargetState(const GrPipeline&);
+
+// GrVkGpu* fGpu;
+
+ // GrVkResources
+ GrVkDescriptorPool* fDescriptorPool;
+ GrVkPipeline* fPipeline;
+
+ // Used for binding DescriptorSets to the command buffer but does not need to survive during
+ // command buffer execution. Thus this is not need to be a GrVkResource.
+ VkPipelineLayout fPipelineLayout;
+
+ // The first set (index 0) will be used for samplers and the second set (index 1) will be
+ // used for uniform buffers.
+ // The DSLayouts only are needed for allocating the descriptor sets and must survive until after
+ // descriptor sets have been updated. Thus the lifetime of the layouts will just be the life of
+ //the GrVkProgram.
+ VkDescriptorSetLayout fDSLayout[2];
+ // The DescriptorSets need to survive until the gpu has finished all draws that use them.
+ // However, they will only be freed by the descriptor pool. Thus by simply keeping the
+ // descriptor pool alive through the draw, the descritor sets will also stay alive. Thus we do
+ // not need a GrVkResource versions of VkDescriptorSet.
+ VkDescriptorSet fDescriptorSets[2];
+
+ SkAutoTDelete<GrVkUniformBuffer> fVertexUniformBuffer;
+ SkAutoTDelete<GrVkUniformBuffer> fFragmentUniformBuffer;
+
+ // GrVkResources used for sampling textures
+ SkTDArray<GrVkSampler*> fSamplers;
+ SkTDArray<const GrVkImageView*> fTextureViews;
+ SkTDArray<const GrVkImage::Resource*> fTextures;
+
+ // Tracks the current render target uniforms stored in the vertex buffer.
+ RenderTargetState fRenderTargetState;
+ BuiltinUniformHandles fBuiltinUniformHandles;
+
+ // Processors in the program
+ SkAutoTDelete<GrGLSLPrimitiveProcessor> fGeometryProcessor;
+ SkAutoTDelete<GrGLSLXferProcessor> fXferProcessor;
+ GrGLSLFragProcs fFragmentProcessors;
+
+ GrVkProgramDataManager fProgramDataManager;
+
+#ifdef SK_DEBUG
+ int fNumSamplers;
+#endif
+
+ friend class GrVkProgramBuilder;
+};
+
+#endif
diff --git a/src/gpu/vk/GrVkProgramBuilder.cpp b/src/gpu/vk/GrVkProgramBuilder.cpp
new file mode 100644
index 0000000000..916b8c3b5f
--- /dev/null
+++ b/src/gpu/vk/GrVkProgramBuilder.cpp
@@ -0,0 +1,323 @@
+/*
+* 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 "vk/GrVkProgramBuilder.h"
+
+#include "vk/GrVkGpu.h"
+#include "vk/GrVkRenderPass.h"
+#include "vk/GrVkProgram.h"
+
+GrVkProgram* GrVkProgramBuilder::CreateProgram(GrVkGpu* gpu,
+ const DrawArgs& args,
+ GrPrimitiveType primitiveType,
+ const GrVkRenderPass& renderPass) {
+ // create a builder. This will be handed off to effects so they can use it to add
+ // uniforms, varyings, textures, etc
+ GrVkProgramBuilder builder(gpu, args);
+
+ GrGLSLExpr4 inputColor;
+ GrGLSLExpr4 inputCoverage;
+
+ if (!builder.emitAndInstallProcs(&inputColor,
+ &inputCoverage,
+ gpu->vkCaps().maxSampledTextures())) {
+ builder.cleanupFragmentProcessors();
+ return nullptr;
+ }
+
+ return builder.finalize(args, primitiveType, renderPass);
+}
+
+GrVkProgramBuilder::GrVkProgramBuilder(GrVkGpu* gpu, const DrawArgs& args)
+ : INHERITED(args)
+ , fGpu(gpu)
+ , fVaryingHandler(this)
+ , fUniformHandler(this) {
+}
+
+const GrCaps* GrVkProgramBuilder::caps() const {
+ return fGpu->caps();
+}
+const GrGLSLCaps* GrVkProgramBuilder::glslCaps() const {
+ return fGpu->vkCaps().glslCaps();
+}
+
+void GrVkProgramBuilder::finalizeFragmentOutputColor(GrGLSLShaderVar& outputColor) {
+ outputColor.setLayoutQualifier("location = 0");
+}
+
+void GrVkProgramBuilder::emitSamplers(const GrProcessor& processor,
+ GrGLSLTextureSampler::TextureSamplerArray* outSamplers) {
+ int numTextures = processor.numTextures();
+ UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures);
+ SkString name;
+ for (int t = 0; t < numTextures; ++t) {
+ name.printf("%d", t);
+ localSamplerUniforms[t] =
+ fUniformHandler.addUniform(kFragment_GrShaderFlag,
+ kSampler2D_GrSLType, kDefault_GrSLPrecision,
+ name.c_str());
+ outSamplers->emplace_back(localSamplerUniforms[t], processor.textureAccess(t));
+ }
+}
+
+VkShaderStageFlags visibility_to_vk_stage_flags(uint32_t visibility) {
+ VkShaderStageFlags flags = 0;
+
+ if (visibility & kVertex_GrShaderFlag) {
+ flags |= VK_SHADER_STAGE_VERTEX_BIT;
+ }
+ if (visibility & kGeometry_GrShaderFlag) {
+ flags |= VK_SHADER_STAGE_GEOMETRY_BIT;
+ }
+ if (visibility & kFragment_GrShaderFlag) {
+ flags |= VK_SHADER_STAGE_FRAGMENT_BIT;
+ }
+ return flags;
+}
+
+shaderc_shader_kind vk_shader_stage_to_shaderc_kind(VkShaderStageFlagBits stage) {
+ if (VK_SHADER_STAGE_VERTEX_BIT == stage) {
+ return shaderc_glsl_vertex_shader;
+ }
+ SkASSERT(VK_SHADER_STAGE_FRAGMENT_BIT == stage);
+ return shaderc_glsl_fragment_shader;
+}
+
+bool GrVkProgramBuilder::CreateVkShaderModule(const GrVkGpu* gpu,
+ VkShaderStageFlagBits stage,
+ const GrGLSLShaderBuilder& builder,
+ VkShaderModule* shaderModule,
+ VkPipelineShaderStageCreateInfo* stageInfo) {
+ SkString shaderString;
+ for (int i = 0; i < builder.fCompilerStrings.count(); ++i) {
+ if (builder.fCompilerStrings[i]) {
+ shaderString.append(builder.fCompilerStrings[i]);
+ shaderString.append("\n");
+ }
+ }
+
+ shaderc_compiler_t compiler = gpu->shadercCompiler();
+
+ shaderc_compile_options_t options = shaderc_compile_options_initialize();
+ shaderc_compile_options_set_forced_version_profile(options, 140, shaderc_profile_none);
+
+ shaderc_shader_kind shadercStage = vk_shader_stage_to_shaderc_kind(stage);
+ shaderc_compilation_result_t result = shaderc_compile_into_spv(compiler,
+ shaderString.c_str(),
+ strlen(shaderString.c_str()),
+ shadercStage,
+ "shader",
+ "main",
+ options);
+ shaderc_compile_options_release(options);
+#ifdef SK_DEBUG
+ if (shaderc_result_get_num_errors(result)) {
+ SkDebugf("%s\n", shaderString.c_str());
+ SkDebugf("%s\n", shaderc_result_get_error_message(result));
+ return false;
+ }
+#endif
+
+ VkShaderModuleCreateInfo moduleCreateInfo;
+ memset(&moduleCreateInfo, 0, sizeof(VkShaderModuleCreateInfo));
+ moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ moduleCreateInfo.pNext = nullptr;
+ moduleCreateInfo.flags = 0;
+ moduleCreateInfo.codeSize = shaderc_result_get_length(result);
+ moduleCreateInfo.pCode = (const uint32_t*)shaderc_result_get_bytes(result);
+
+ VkResult err = GR_VK_CALL(gpu->vkInterface(), CreateShaderModule(gpu->device(),
+ &moduleCreateInfo,
+ nullptr,
+ shaderModule));
+ shaderc_result_release(result);
+ if (err) {
+ return false;
+ }
+
+ memset(stageInfo, 0, sizeof(VkPipelineShaderStageCreateInfo));
+ stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ stageInfo->pNext = nullptr;
+ stageInfo->flags = 0;
+ stageInfo->stage = stage;
+ stageInfo->module = *shaderModule;
+ stageInfo->pName = "main";
+ stageInfo->pSpecializationInfo = nullptr;
+
+ return true;
+}
+
+GrVkProgram* GrVkProgramBuilder::finalize(const DrawArgs& args,
+ GrPrimitiveType primitiveType,
+ const GrVkRenderPass& renderPass) {
+ VkDescriptorSetLayout dsLayout[2];
+ VkPipelineLayout pipelineLayout;
+ VkShaderModule vertShaderModule;
+ VkShaderModule fragShaderModule;
+
+ uint32_t numSamplers = fSamplerUniforms.count();
+
+ SkAutoTDeleteArray<VkDescriptorSetLayoutBinding> dsSamplerBindings(
+ new VkDescriptorSetLayoutBinding[numSamplers]);
+ for (uint32_t i = 0; i < numSamplers; ++i) {
+ UniformHandle uniHandle = fSamplerUniforms[i];
+ GrVkUniformHandler::UniformInfo uniformInfo = fUniformHandler.getUniformInfo(uniHandle);
+ SkASSERT(kSampler2D_GrSLType == uniformInfo.fVariable.getType());
+ SkASSERT(0 == uniformInfo.fSetNumber);
+ SkASSERT(uniformInfo.fBinding == i);
+ dsSamplerBindings[i].binding = uniformInfo.fBinding;
+ dsSamplerBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ dsSamplerBindings[i].descriptorCount = 1;
+ dsSamplerBindings[i].stageFlags = visibility_to_vk_stage_flags(uniformInfo.fVisibility);
+ dsSamplerBindings[i].pImmutableSamplers = nullptr;
+ }
+
+ VkDescriptorSetLayoutCreateInfo dsSamplerLayoutCreateInfo;
+ memset(&dsSamplerLayoutCreateInfo, 0, sizeof(VkDescriptorSetLayoutCreateInfo));
+ dsSamplerLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ dsSamplerLayoutCreateInfo.pNext = nullptr;
+ dsSamplerLayoutCreateInfo.flags = 0;
+ dsSamplerLayoutCreateInfo.bindingCount = fSamplerUniforms.count();
+ // Setting to nullptr fixes an error in the param checker validation layer. Even though
+ // bindingCount is 0 (which is valid), it still tries to validate pBindings unless it is null.
+ dsSamplerLayoutCreateInfo.pBindings = fSamplerUniforms.count() ? dsSamplerBindings.get() :
+ nullptr;
+
+ GR_VK_CALL_ERRCHECK(fGpu->vkInterface(),
+ CreateDescriptorSetLayout(fGpu->device(),
+ &dsSamplerLayoutCreateInfo,
+ nullptr,
+ &dsLayout[GrVkUniformHandler::kSamplerDescSet]));
+
+ // Create Uniform Buffer Descriptor
+ // We always attach uniform buffers to descriptor set 1. The vertex uniform buffer will have
+ // binding 0 and the fragment binding 1.
+ VkDescriptorSetLayoutBinding dsUniBindings[2];
+ memset(&dsUniBindings, 0, 2 * sizeof(VkDescriptorSetLayoutBinding));
+ dsUniBindings[0].binding = GrVkUniformHandler::kVertexBinding;
+ dsUniBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ dsUniBindings[0].descriptorCount = fUniformHandler.hasVertexUniforms() ? 1 : 0;
+ dsUniBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+ dsUniBindings[0].pImmutableSamplers = nullptr;
+ dsUniBindings[1].binding = GrVkUniformHandler::kFragBinding;
+ dsUniBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ dsUniBindings[1].descriptorCount = fUniformHandler.hasFragmentUniforms() ? 1 : 0;
+ dsUniBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+ dsUniBindings[1].pImmutableSamplers = nullptr;
+
+ VkDescriptorSetLayoutCreateInfo dsUniformLayoutCreateInfo;
+ memset(&dsUniformLayoutCreateInfo, 0, sizeof(VkDescriptorSetLayoutCreateInfo));
+ dsUniformLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ dsUniformLayoutCreateInfo.pNext = nullptr;
+ dsUniformLayoutCreateInfo.flags = 0;
+ dsUniformLayoutCreateInfo.bindingCount = 2;
+ dsUniformLayoutCreateInfo.pBindings = dsUniBindings;
+
+ GR_VK_CALL_ERRCHECK(fGpu->vkInterface(), CreateDescriptorSetLayout(
+ fGpu->device(),
+ &dsUniformLayoutCreateInfo,
+ nullptr,
+ &dsLayout[GrVkUniformHandler::kUniformBufferDescSet]));
+
+ // 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;
+
+ GR_VK_CALL_ERRCHECK(fGpu->vkInterface(), CreatePipelineLayout(fGpu->device(),
+ &layoutCreateInfo,
+ nullptr,
+ &pipelineLayout));
+
+ // We need to enable the following extensions so that the compiler can correctly make spir-v
+ // from our glsl shaders.
+ fVS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
+ fFS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
+ fVS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
+ fFS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
+
+ this->finalizeShaders();
+
+ VkPipelineShaderStageCreateInfo shaderStageInfo[2];
+ SkAssertResult(CreateVkShaderModule(fGpu,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ fVS,
+ &vertShaderModule,
+ &shaderStageInfo[0]));
+
+ SkAssertResult(CreateVkShaderModule(fGpu,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ fFS,
+ &fragShaderModule,
+ &shaderStageInfo[1]));
+
+ GrVkResourceProvider& resourceProvider = fGpu->resourceProvider();
+ GrVkPipeline* pipeline = resourceProvider.createPipeline(*args.fPipeline,
+ *args.fPrimitiveProcessor,
+ shaderStageInfo,
+ 2,
+ primitiveType,
+ renderPass,
+ pipelineLayout);
+ GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), vertShaderModule,
+ nullptr));
+ GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), fragShaderModule,
+ nullptr));
+
+ if (!pipeline) {
+ GR_VK_CALL(fGpu->vkInterface(), DestroyPipelineLayout(fGpu->device(), pipelineLayout,
+ nullptr));
+ GR_VK_CALL(fGpu->vkInterface(), DestroyDescriptorSetLayout(fGpu->device(), dsLayout[0],
+ nullptr));
+ GR_VK_CALL(fGpu->vkInterface(), DestroyDescriptorSetLayout(fGpu->device(), dsLayout[1],
+ nullptr));
+ return nullptr;
+ }
+
+
+ GrVkDescriptorPool::DescriptorTypeCounts typeCounts;
+ typeCounts.setTypeCount(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2);
+ SkASSERT(numSamplers < 256);
+ typeCounts.setTypeCount(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, (uint8_t)numSamplers);
+ GrVkDescriptorPool* descriptorPool =
+ fGpu->resourceProvider().findOrCreateCompatibleDescriptorPool(typeCounts);
+
+ VkDescriptorSetAllocateInfo dsAllocateInfo;
+ memset(&dsAllocateInfo, 0, sizeof(VkDescriptorSetAllocateInfo));
+ dsAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ dsAllocateInfo.pNext = nullptr;
+ dsAllocateInfo.descriptorPool = descriptorPool->descPool();
+ dsAllocateInfo.descriptorSetCount = 2;
+ dsAllocateInfo.pSetLayouts = dsLayout;
+
+ VkDescriptorSet descriptorSets[2];
+ GR_VK_CALL_ERRCHECK(fGpu->vkInterface(), AllocateDescriptorSets(fGpu->device(),
+ &dsAllocateInfo,
+ descriptorSets));
+
+ return new GrVkProgram(fGpu,
+ pipeline,
+ pipelineLayout,
+ dsLayout,
+ descriptorPool,
+ descriptorSets,
+ fUniformHandles,
+ fUniformHandler.fUniforms,
+ fUniformHandler.fCurrentVertexUBOOffset,
+ fUniformHandler.fCurrentFragmentUBOOffset,
+ numSamplers,
+ fGeometryProcessor,
+ fXferProcessor,
+ fFragmentProcessors);
+}
diff --git a/src/gpu/vk/GrVkProgramDataManager.h b/src/gpu/vk/GrVkProgramDataManager.h
new file mode 100644
index 0000000000..800625902a
--- /dev/null
+++ b/src/gpu/vk/GrVkProgramDataManager.h
@@ -0,0 +1,70 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef GrVkProgramDataManager_DEFINED
+#define GrVkProgramDataManager_DEFINED
+
+#include "glsl/GrGLSLProgramDataManager.h"
+
+#include "vk/GrVkUniformHandler.h"
+
+class GrVkGpu;
+class GrVkUniformBuffer;
+
+class GrVkProgramDataManager : public GrGLSLProgramDataManager {
+public:
+ typedef GrVkUniformHandler::UniformInfoArray UniformInfoArray;
+
+ GrVkProgramDataManager(const UniformInfoArray&,
+ uint32_t vertexUniformSize,
+ uint32_t fragmentUniformSize);
+
+ void set1f(UniformHandle, float v0) const override;
+ void set1fv(UniformHandle, int arrayCount, const float v[]) const override;
+ void set2f(UniformHandle, float, float) const override;
+ void set2fv(UniformHandle, int arrayCount, const float v[]) const override;
+ void set3f(UniformHandle, float, float, float) const override;
+ void set3fv(UniformHandle, int arrayCount, const float v[]) const override;
+ void set4f(UniformHandle, float, float, float, float) const override;
+ void set4fv(UniformHandle, int arrayCount, const float v[]) const override;
+ // matrices are column-major, the first two upload a single matrix, the latter two upload
+ // arrayCount matrices into a uniform array.
+ void setMatrix3f(UniformHandle, const float matrix[]) const override;
+ void setMatrix4f(UniformHandle, const float matrix[]) const override;
+ void setMatrix3fv(UniformHandle, int arrayCount, const float matrices[]) const override;
+ void setMatrix4fv(UniformHandle, int arrayCount, const float matrices[]) const override;
+
+ // for nvpr only
+ void setPathFragmentInputTransform(VaryingHandle u, int components,
+ const SkMatrix& matrix) const override {
+ SkFAIL("Only supported in NVPR, which is not in vulkan");
+ }
+
+ void uploadUniformBuffers(const GrVkGpu* gpu,
+ GrVkUniformBuffer* vertexBuffer,
+ GrVkUniformBuffer* fragmentBuffer) const;
+private:
+ struct Uniform {
+ uint32_t fBinding;
+ uint32_t fOffset;
+ SkDEBUGCODE(
+ GrSLType fType;
+ int fArrayCount;
+ uint32_t fSetNumber;
+ );
+ };
+
+ uint32_t fVertexUniformSize;
+ uint32_t fFragmentUniformSize;
+
+ SkTArray<Uniform, true> fUniforms;
+
+ mutable SkAutoMalloc fVertexUniformData;
+ mutable SkAutoMalloc fFragmentUniformData;
+};
+
+#endif
diff --git a/src/gpu/vk/GrVkSampler.cpp b/src/gpu/vk/GrVkSampler.cpp
new file mode 100644
index 0000000000..4bba66268b
--- /dev/null
+++ b/src/gpu/vk/GrVkSampler.cpp
@@ -0,0 +1,74 @@
+/*
+* 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 "GrVkSampler.h"
+
+#include "GrTextureAccess.h"
+#include "GrVkGpu.h"
+
+static inline VkSamplerAddressMode tile_to_vk_sampler_address(SkShader::TileMode tm) {
+ static const VkSamplerAddressMode gWrapModes[] = {
+ VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
+ VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT
+ };
+ GR_STATIC_ASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gWrapModes));
+ GR_STATIC_ASSERT(0 == SkShader::kClamp_TileMode);
+ GR_STATIC_ASSERT(1 == SkShader::kRepeat_TileMode);
+ GR_STATIC_ASSERT(2 == SkShader::kMirror_TileMode);
+ return gWrapModes[tm];
+}
+
+GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrTextureAccess& textureAccess) {
+
+ static VkFilter vkMinFilterModes[] = {
+ VK_FILTER_NEAREST,
+ VK_FILTER_LINEAR,
+ VK_FILTER_LINEAR
+ };
+ static VkFilter vkMagFilterModes[] = {
+ VK_FILTER_NEAREST,
+ VK_FILTER_LINEAR,
+ VK_FILTER_LINEAR
+ };
+
+ const GrTextureParams& params = textureAccess.getParams();
+
+ VkSamplerCreateInfo createInfo;
+ memset(&createInfo, 0, sizeof(VkSamplerCreateInfo));
+ createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+ createInfo.pNext = 0;
+ createInfo.flags = 0;
+ createInfo.magFilter = vkMagFilterModes[params.filterMode()];
+ createInfo.minFilter = vkMinFilterModes[params.filterMode()];
+ createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
+ createInfo.addressModeU = tile_to_vk_sampler_address(params.getTileModeX());
+ createInfo.addressModeV = tile_to_vk_sampler_address(params.getTileModeY());
+ createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; // Shouldn't matter
+ createInfo.mipLodBias = 0.0f;
+ createInfo.anisotropyEnable = VK_FALSE;
+ createInfo.maxAnisotropy = 1.0f;
+ createInfo.compareEnable = VK_FALSE;
+ createInfo.compareOp = VK_COMPARE_OP_NEVER;
+ createInfo.minLod = 0.0f;
+ createInfo.maxLod = 0.0f;
+ createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+ createInfo.unnormalizedCoordinates = VK_FALSE;
+
+ VkSampler sampler;
+ GR_VK_CALL_ERRCHECK(gpu->vkInterface(), CreateSampler(gpu->device(),
+ &createInfo,
+ nullptr,
+ &sampler));
+
+ return new GrVkSampler(sampler);
+}
+
+void GrVkSampler::freeGPUData(const GrVkGpu* gpu) const {
+ SkASSERT(fSampler);
+ GR_VK_CALL(gpu->vkInterface(), DestroySampler(gpu->device(), fSampler, nullptr));
+}
diff --git a/src/gpu/vk/GrVkVaryingHandler.cpp b/src/gpu/vk/GrVkVaryingHandler.cpp
new file mode 100644
index 0000000000..71d548e439
--- /dev/null
+++ b/src/gpu/vk/GrVkVaryingHandler.cpp
@@ -0,0 +1,26 @@
+/*
+* 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 "GrVkVaryingHandler.h"
+
+
+void finalize_helper(GrVkVaryingHandler::VarArray& vars) {
+ for (int i = 0; i < vars.count(); ++i) {
+ SkString location;
+ location.appendf("location = %d", i);
+ vars[i].setLayoutQualifier(location.c_str());
+ }
+}
+
+void GrVkVaryingHandler::onFinalize() {
+ finalize_helper(fVertexInputs);
+ finalize_helper(fVertexOutputs);
+ finalize_helper(fGeomInputs);
+ finalize_helper(fGeomOutputs);
+ finalize_helper(fFragInputs);
+ finalize_helper(fFragOutputs);
+}