blob: 2a2c699f75ef7d996dd28527a12fa942c63e2dc9 [file] [log] [blame]
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ContextVk.cpp:
// Implements the class methods for ContextVk.
//
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "common/bitset_utils.h"
#include "common/debug.h"
#include "libANGLE/Program.h"
#include "libANGLE/renderer/vulkan/BufferVk.h"
#include "libANGLE/renderer/vulkan/CompilerVk.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/DeviceVk.h"
#include "libANGLE/renderer/vulkan/FenceNVVk.h"
#include "libANGLE/renderer/vulkan/FenceSyncVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/ImageVk.h"
#include "libANGLE/renderer/vulkan/ProgramVk.h"
#include "libANGLE/renderer/vulkan/QueryVk.h"
#include "libANGLE/renderer/vulkan/RenderbufferVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/SamplerVk.h"
#include "libANGLE/renderer/vulkan/ShaderVk.h"
#include "libANGLE/renderer/vulkan/TextureVk.h"
#include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
#include "libANGLE/renderer/vulkan/VertexArrayVk.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
namespace rx
{
ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
: ContextImpl(state), mRenderer(renderer), mCurrentDrawMode(GL_NONE)
{
}
ContextVk::~ContextVk()
{
invalidateCurrentPipeline();
}
gl::Error ContextVk::initialize()
{
return gl::NoError();
}
gl::Error ContextVk::flush()
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION);
}
gl::Error ContextVk::finish()
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION);
}
gl::Error ContextVk::initPipeline()
{
ASSERT(!mCurrentPipeline.valid());
VkDevice device = mRenderer->getDevice();
const auto &state = mState.getState();
const auto &programGL = state.getProgram();
const auto &vao = state.getVertexArray();
const auto &attribs = vao->getVertexAttributes();
const auto &bindings = vao->getVertexBindings();
const auto &programVk = GetImplAs<ProgramVk>(programGL);
const auto *drawFBO = state.getDrawFramebuffer();
FramebufferVk *vkFBO = GetImplAs<FramebufferVk>(drawFBO);
// { vertex, fragment }
VkPipelineShaderStageCreateInfo shaderStages[2];
shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStages[0].pNext = nullptr;
shaderStages[0].flags = 0;
shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
shaderStages[0].module = programVk->getLinkedVertexModule().getHandle();
shaderStages[0].pName = "main";
shaderStages[0].pSpecializationInfo = nullptr;
shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStages[1].pNext = nullptr;
shaderStages[1].flags = 0;
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
shaderStages[1].module = programVk->getLinkedFragmentModule().getHandle();
shaderStages[1].pName = "main";
shaderStages[1].pSpecializationInfo = nullptr;
// Process vertex attributes
// TODO(jmadill): Caching with dirty bits.
std::vector<VkVertexInputBindingDescription> vertexBindings;
std::vector<VkVertexInputAttributeDescription> vertexAttribs;
for (auto attribIndex : programGL->getActiveAttribLocationsMask())
{
const auto &attrib = attribs[attribIndex];
const auto &binding = bindings[attrib.bindingIndex];
if (attrib.enabled)
{
VkVertexInputBindingDescription bindingDesc;
bindingDesc.binding = static_cast<uint32_t>(vertexBindings.size());
bindingDesc.stride = static_cast<uint32_t>(gl::ComputeVertexAttributeTypeSize(attrib));
bindingDesc.inputRate =
(binding.divisor > 0 ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX);
gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib);
VkVertexInputAttributeDescription attribDesc;
attribDesc.binding = bindingDesc.binding;
attribDesc.format = vk::GetNativeVertexFormat(vertexFormatType);
attribDesc.location = static_cast<uint32_t>(attribIndex);
attribDesc.offset =
static_cast<uint32_t>(ComputeVertexAttributeOffset(attrib, binding));
vertexBindings.push_back(bindingDesc);
vertexAttribs.push_back(attribDesc);
}
else
{
UNIMPLEMENTED();
}
}
// TODO(jmadill): Validate with ASSERT against physical device limits/caps?
VkPipelineVertexInputStateCreateInfo vertexInputState;
vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputState.pNext = nullptr;
vertexInputState.flags = 0;
vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexBindings.size());
vertexInputState.pVertexBindingDescriptions = vertexBindings.data();
vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexAttribs.size());
vertexInputState.pVertexAttributeDescriptions = vertexAttribs.data();
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState;
inputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyState.pNext = nullptr;
inputAssemblyState.flags = 0;
inputAssemblyState.topology = gl_vk::GetPrimitiveTopology(mCurrentDrawMode);
inputAssemblyState.primitiveRestartEnable = VK_FALSE;
const gl::Rectangle &viewportGL = state.getViewport();
VkViewport viewportVk;
viewportVk.x = static_cast<float>(viewportGL.x);
viewportVk.y = static_cast<float>(viewportGL.y);
viewportVk.width = static_cast<float>(viewportGL.width);
viewportVk.height = static_cast<float>(viewportGL.height);
viewportVk.minDepth = state.getNearPlane();
viewportVk.maxDepth = state.getFarPlane();
// TODO(jmadill): Scissor.
VkRect2D scissorVk;
scissorVk.offset.x = viewportGL.x;
scissorVk.offset.y = viewportGL.y;
scissorVk.extent.width = viewportGL.width;
scissorVk.extent.height = viewportGL.height;
VkPipelineViewportStateCreateInfo viewportState;
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.pNext = nullptr;
viewportState.flags = 0;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewportVk;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissorVk;
// TODO(jmadill): Extra rasterizer state features.
VkPipelineRasterizationStateCreateInfo rasterState;
rasterState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterState.pNext = nullptr;
rasterState.flags = 0;
rasterState.depthClampEnable = VK_FALSE;
rasterState.rasterizerDiscardEnable = VK_FALSE;
rasterState.polygonMode = VK_POLYGON_MODE_FILL;
rasterState.cullMode = gl_vk::GetCullMode(state.getRasterizerState());
rasterState.frontFace = gl_vk::GetFrontFace(state.getRasterizerState().frontFace);
rasterState.depthBiasEnable = VK_FALSE;
rasterState.depthBiasConstantFactor = 0.0f;
rasterState.depthBiasClamp = 0.0f;
rasterState.depthBiasSlopeFactor = 0.0f;
rasterState.lineWidth = state.getLineWidth();
// TODO(jmadill): Multisample state.
VkPipelineMultisampleStateCreateInfo multisampleState;
multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleState.pNext = nullptr;
multisampleState.flags = 0;
multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
multisampleState.sampleShadingEnable = VK_FALSE;
multisampleState.minSampleShading = 0.0f;
multisampleState.pSampleMask = nullptr;
multisampleState.alphaToCoverageEnable = VK_FALSE;
multisampleState.alphaToOneEnable = VK_FALSE;
// TODO(jmadill): Depth/stencil state.
// TODO(jmadill): Blend state/MRT.
VkPipelineColorBlendAttachmentState blendAttachmentState;
blendAttachmentState.blendEnable = VK_FALSE;
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
VkPipelineColorBlendStateCreateInfo blendState;
blendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
blendState.pNext = 0;
blendState.flags = 0;
blendState.logicOpEnable = VK_FALSE;
blendState.logicOp = VK_LOGIC_OP_CLEAR;
blendState.attachmentCount = 1;
blendState.pAttachments = &blendAttachmentState;
blendState.blendConstants[0] = 0.0f;
blendState.blendConstants[1] = 0.0f;
blendState.blendConstants[2] = 0.0f;
blendState.blendConstants[3] = 0.0f;
// TODO(jmadill): Dynamic state.
vk::RenderPass *renderPass = nullptr;
ANGLE_TRY_RESULT(vkFBO->getRenderPass(device), renderPass);
ASSERT(renderPass && renderPass->valid());
vk::PipelineLayout *pipelineLayout = nullptr;
ANGLE_TRY_RESULT(programVk->getPipelineLayout(device), pipelineLayout);
ASSERT(pipelineLayout && pipelineLayout->valid());
VkGraphicsPipelineCreateInfo pipelineInfo;
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.pNext = nullptr;
pipelineInfo.flags = 0;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStages;
pipelineInfo.pVertexInputState = &vertexInputState;
pipelineInfo.pInputAssemblyState = &inputAssemblyState;
pipelineInfo.pTessellationState = nullptr;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterState;
pipelineInfo.pMultisampleState = &multisampleState;
pipelineInfo.pDepthStencilState = nullptr;
pipelineInfo.pColorBlendState = &blendState;
pipelineInfo.pDynamicState = nullptr;
pipelineInfo.layout = pipelineLayout->getHandle();
pipelineInfo.renderPass = renderPass->getHandle();
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = 0;
vk::Pipeline newPipeline;
ANGLE_TRY(newPipeline.initGraphics(device, pipelineInfo));
mCurrentPipeline.retain(device, std::move(newPipeline));
return gl::NoError();
}
gl::Error ContextVk::drawArrays(GLenum mode, GLint first, GLsizei count)
{
if (mode != mCurrentDrawMode)
{
invalidateCurrentPipeline();
mCurrentDrawMode = mode;
}
if (!mCurrentPipeline.valid())
{
ANGLE_TRY(initPipeline());
ASSERT(mCurrentPipeline.valid());
}
VkDevice device = mRenderer->getDevice();
const auto &state = mState.getState();
const auto &programGL = state.getProgram();
const auto &vao = state.getVertexArray();
const auto &attribs = vao->getVertexAttributes();
const auto &bindings = vao->getVertexBindings();
const auto *drawFBO = state.getDrawFramebuffer();
FramebufferVk *vkFBO = GetImplAs<FramebufferVk>(drawFBO);
Serial queueSerial = mRenderer->getCurrentQueueSerial();
// Process vertex attributes
// TODO(jmadill): Caching with dirty bits.
std::vector<VkBuffer> vertexHandles;
std::vector<VkDeviceSize> vertexOffsets;
for (auto attribIndex : programGL->getActiveAttribLocationsMask())
{
const auto &attrib = attribs[attribIndex];
const auto &binding = bindings[attrib.bindingIndex];
if (attrib.enabled)
{
// TODO(jmadill): Offset handling.
gl::Buffer *bufferGL = binding.buffer.get();
ASSERT(bufferGL);
BufferVk *bufferVk = GetImplAs<BufferVk>(bufferGL);
vertexHandles.push_back(bufferVk->getVkBuffer().getHandle());
vertexOffsets.push_back(0);
bufferVk->setQueueSerial(queueSerial);
}
else
{
UNIMPLEMENTED();
}
}
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mRenderer->getStartedCommandBuffer(&commandBuffer));
ANGLE_TRY(vkFBO->beginRenderPass(device, commandBuffer, queueSerial, state));
commandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mCurrentPipeline);
commandBuffer->bindVertexBuffers(0, vertexHandles, vertexOffsets);
commandBuffer->draw(count, 1, first, 0);
commandBuffer->endRenderPass();
return gl::NoError();
}
gl::Error ContextVk::drawArraysInstanced(GLenum mode,
GLint first,
GLsizei count,
GLsizei instanceCount)
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION);
}
gl::Error ContextVk::drawElements(GLenum mode,
GLsizei count,
GLenum type,
const void *indices,
const gl::IndexRange &indexRange)
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION);
}
gl::Error ContextVk::drawElementsInstanced(GLenum mode,
GLsizei count,
GLenum type,
const void *indices,
GLsizei instances,
const gl::IndexRange &indexRange)
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION);
}
gl::Error ContextVk::drawRangeElements(GLenum mode,
GLuint start,
GLuint end,
GLsizei count,
GLenum type,
const void *indices,
const gl::IndexRange &indexRange)
{
return gl::NoError();
}
VkDevice ContextVk::getDevice() const
{
return mRenderer->getDevice();
}
vk::Error ContextVk::getStartedCommandBuffer(vk::CommandBuffer **commandBufferOut)
{
return mRenderer->getStartedCommandBuffer(commandBufferOut);
}
vk::Error ContextVk::submitCommands(vk::CommandBuffer *commandBuffer)
{
setQueueSerial(mRenderer->getCurrentQueueSerial());
ANGLE_TRY(mRenderer->submitCommandBuffer(commandBuffer));
return vk::NoError();
}
gl::Error ContextVk::drawArraysIndirect(GLenum mode, const void *indirect)
{
UNIMPLEMENTED();
return gl::InternalError() << "DrawArraysIndirect hasn't been implemented for vulkan backend.";
}
gl::Error ContextVk::drawElementsIndirect(GLenum mode, GLenum type, const void *indirect)
{
UNIMPLEMENTED();
return gl::InternalError()
<< "DrawElementsIndirect hasn't been implemented for vulkan backend.";
}
GLenum ContextVk::getResetStatus()
{
UNIMPLEMENTED();
return GL_NO_ERROR;
}
std::string ContextVk::getVendorString() const
{
UNIMPLEMENTED();
return std::string();
}
std::string ContextVk::getRendererDescription() const
{
return mRenderer->getRendererDescription();
}
void ContextVk::insertEventMarker(GLsizei length, const char *marker)
{
UNIMPLEMENTED();
}
void ContextVk::pushGroupMarker(GLsizei length, const char *marker)
{
UNIMPLEMENTED();
}
void ContextVk::popGroupMarker()
{
UNIMPLEMENTED();
}
void ContextVk::syncState(const gl::State::DirtyBits &dirtyBits)
{
// TODO(jmadill): Vulkan dirty bits.
if (dirtyBits.any())
{
invalidateCurrentPipeline();
}
}
GLint ContextVk::getGPUDisjoint()
{
UNIMPLEMENTED();
return GLint();
}
GLint64 ContextVk::getTimestamp()
{
UNIMPLEMENTED();
return GLint64();
}
void ContextVk::onMakeCurrent(const gl::ContextState & /*data*/)
{
}
const gl::Caps &ContextVk::getNativeCaps() const
{
return mRenderer->getNativeCaps();
}
const gl::TextureCapsMap &ContextVk::getNativeTextureCaps() const
{
return mRenderer->getNativeTextureCaps();
}
const gl::Extensions &ContextVk::getNativeExtensions() const
{
return mRenderer->getNativeExtensions();
}
const gl::Limitations &ContextVk::getNativeLimitations() const
{
return mRenderer->getNativeLimitations();
}
CompilerImpl *ContextVk::createCompiler()
{
return new CompilerVk();
}
ShaderImpl *ContextVk::createShader(const gl::ShaderState &state)
{
return new ShaderVk(state);
}
ProgramImpl *ContextVk::createProgram(const gl::ProgramState &state)
{
return new ProgramVk(state);
}
FramebufferImpl *ContextVk::createFramebuffer(const gl::FramebufferState &state)
{
return FramebufferVk::CreateUserFBO(state);
}
TextureImpl *ContextVk::createTexture(const gl::TextureState &state)
{
return new TextureVk(state);
}
RenderbufferImpl *ContextVk::createRenderbuffer()
{
return new RenderbufferVk();
}
BufferImpl *ContextVk::createBuffer(const gl::BufferState &state)
{
return new BufferVk(state);
}
VertexArrayImpl *ContextVk::createVertexArray(const gl::VertexArrayState &state)
{
return new VertexArrayVk(state);
}
QueryImpl *ContextVk::createQuery(GLenum type)
{
return new QueryVk(type);
}
FenceNVImpl *ContextVk::createFenceNV()
{
return new FenceNVVk();
}
FenceSyncImpl *ContextVk::createFenceSync()
{
return new FenceSyncVk();
}
TransformFeedbackImpl *ContextVk::createTransformFeedback(const gl::TransformFeedbackState &state)
{
return new TransformFeedbackVk(state);
}
SamplerImpl *ContextVk::createSampler()
{
return new SamplerVk();
}
std::vector<PathImpl *> ContextVk::createPaths(GLsizei)
{
return std::vector<PathImpl *>();
}
// TODO(jmadill): Use pipeline cache.
void ContextVk::invalidateCurrentPipeline()
{
mRenderer->enqueueGarbageOrDeleteNow(*this, mCurrentPipeline);
}
gl::Error ContextVk::dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ)
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION);
}
} // namespace rx