Commit df68a6f0 by Jamie Madill Committed by Commit Bot

Vulkan: Implement a simple graphics pipeline.

BUG=angleproject:1580 Change-Id: Iceaed896db22dc9eefa3f1bee7d6142fcfb20368 Reviewed-on: https://chromium-review.googlesource.com/412267 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent b3280707
...@@ -403,6 +403,7 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -403,6 +403,7 @@ class Program final : angle::NonCopyable, public LabeledObject
{ {
return mState.mSamplerBindings; return mState.mSamplerBindings;
} }
const ProgramState &getState() const { return mState; }
private: private:
class Bindings final : angle::NonCopyable class Bindings final : angle::NonCopyable
......
...@@ -125,6 +125,6 @@ class VertexArray final : public LabeledObject ...@@ -125,6 +125,6 @@ class VertexArray final : public LabeledObject
rx::VertexArrayImpl *mVertexArray; rx::VertexArrayImpl *mVertexArray;
}; };
} } // namespace gl
#endif // LIBANGLE_VERTEXARRAY_H_ #endif // LIBANGLE_VERTEXARRAY_H_
...@@ -163,4 +163,9 @@ vk::Error BufferVk::setDataImpl(const uint8_t *data, size_t size, size_t offset) ...@@ -163,4 +163,9 @@ vk::Error BufferVk::setDataImpl(const uint8_t *data, size_t size, size_t offset)
return vk::NoError(); return vk::NoError();
} }
const vk::Buffer &BufferVk::getVkBuffer() const
{
return mBuffer;
}
} // namespace rx } // namespace rx
...@@ -46,6 +46,8 @@ class BufferVk : public BufferImpl ...@@ -46,6 +46,8 @@ class BufferVk : public BufferImpl
bool primitiveRestartEnabled, bool primitiveRestartEnabled,
gl::IndexRange *outRange) override; gl::IndexRange *outRange) override;
const vk::Buffer &getVkBuffer() const;
private: private:
vk::Error setDataImpl(const uint8_t *data, size_t size, size_t offset); vk::Error setDataImpl(const uint8_t *data, size_t size, size_t offset);
......
...@@ -130,6 +130,7 @@ class ContextVk : public ContextImpl ...@@ -130,6 +130,7 @@ class ContextVk : public ContextImpl
private: private:
RendererVk *mRenderer; RendererVk *mRenderer;
vk::Pipeline mCurrentPipeline;
}; };
} // namespace rx } // namespace rx
......
...@@ -363,10 +363,12 @@ gl::ErrorOrResult<vk::RenderPass *> FramebufferVk::getRenderPass(VkDevice device ...@@ -363,10 +363,12 @@ gl::ErrorOrResult<vk::RenderPass *> FramebufferVk::getRenderPass(VkDevice device
colorDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; colorDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorDesc.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
// We might want to transition directly to PRESENT_SRC for Surface attachments.
colorDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorRef.attachment = static_cast<uint32_t>(colorAttachments.size()) - 1u; colorRef.attachment = static_cast<uint32_t>(colorAttachments.size()) - 1u;
colorRef.layout = VK_IMAGE_LAYOUT_GENERAL; colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachmentDescs.push_back(colorDesc); attachmentDescs.push_back(colorDesc);
colorAttachmentRefs.push_back(colorRef); colorAttachmentRefs.push_back(colorRef);
...@@ -497,7 +499,7 @@ gl::ErrorOrResult<vk::Framebuffer *> FramebufferVk::getFramebuffer(VkDevice devi ...@@ -497,7 +499,7 @@ gl::ErrorOrResult<vk::Framebuffer *> FramebufferVk::getFramebuffer(VkDevice devi
framebufferInfo.layers = 1; framebufferInfo.layers = 1;
vk::Framebuffer framebuffer(device); vk::Framebuffer framebuffer(device);
ANGLE_TRY(framebuffer.init(framebufferInfo)); ANGLE_TRY(static_cast<gl::Error>(framebuffer.init(framebufferInfo)));
mFramebuffer = std::move(framebuffer); mFramebuffer = std::move(framebuffer);
...@@ -510,4 +512,41 @@ gl::Error FramebufferVk::getSamplePosition(size_t index, GLfloat *xy) const ...@@ -510,4 +512,41 @@ gl::Error FramebufferVk::getSamplePosition(size_t index, GLfloat *xy) const
return gl::InternalError() << "getSamplePosition is unimplemented."; return gl::InternalError() << "getSamplePosition is unimplemented.";
} }
gl::Error FramebufferVk::beginRenderPass(VkDevice device,
vk::CommandBuffer *commandBuffer,
const gl::State &glState)
{
vk::Framebuffer *framebuffer = nullptr;
ANGLE_TRY_RESULT(getFramebuffer(device), framebuffer);
ASSERT(framebuffer && framebuffer->valid());
vk::RenderPass *renderPass = nullptr;
ANGLE_TRY_RESULT(getRenderPass(device), renderPass);
ASSERT(renderPass && renderPass->valid());
// TODO(jmadill): Proper clear value implementation.
VkClearColorValue colorClear;
memset(&colorClear, 0, sizeof(VkClearColorValue));
colorClear.float32[0] = glState.getColorClearValue().red;
colorClear.float32[1] = glState.getColorClearValue().green;
colorClear.float32[2] = glState.getColorClearValue().blue;
colorClear.float32[3] = glState.getColorClearValue().alpha;
std::vector<VkClearValue> attachmentClearValues;
attachmentClearValues.push_back({colorClear});
// Updated the cached image layout of the attachments in this FBO.
// For a default FBO, we need to call through to the WindowSurfaceVk
// TODO(jmadill): Iterate over all attachments.
ASSERT(mBackbuffer);
RenderTargetVk *renderTarget = nullptr;
ANGLE_TRY(mState.getFirstColorAttachment()->getRenderTarget(&renderTarget));
renderTarget->image->updateLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
ANGLE_TRY(commandBuffer->begin());
commandBuffer->beginRenderPass(*renderPass, *framebuffer, glState.getViewport(),
attachmentClearValues);
return gl::NoError();
}
} // namespace rx } // namespace rx
...@@ -272,4 +272,25 @@ const vk::ShaderModule &ProgramVk::getLinkedFragmentModule() const ...@@ -272,4 +272,25 @@ const vk::ShaderModule &ProgramVk::getLinkedFragmentModule() const
return mLinkedFragmentModule; return mLinkedFragmentModule;
} }
gl::ErrorOrResult<vk::PipelineLayout *> ProgramVk::getPipelineLayout(VkDevice device)
{
vk::PipelineLayout newLayout(device);
// TODO(jmadill): Descriptor sets.
VkPipelineLayoutCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.setLayoutCount = 0;
createInfo.pSetLayouts = nullptr;
createInfo.pushConstantRangeCount = 0;
createInfo.pPushConstantRanges = nullptr;
ANGLE_TRY(newLayout.init(createInfo));
mPipelineLayout = std::move(newLayout);
return &mPipelineLayout;
}
} // namespace rx } // namespace rx
...@@ -101,10 +101,12 @@ class ProgramVk : public ProgramImpl ...@@ -101,10 +101,12 @@ class ProgramVk : public ProgramImpl
const vk::ShaderModule &getLinkedVertexModule() const; const vk::ShaderModule &getLinkedVertexModule() const;
const vk::ShaderModule &getLinkedFragmentModule() const; const vk::ShaderModule &getLinkedFragmentModule() const;
gl::ErrorOrResult<vk::PipelineLayout *> getPipelineLayout(VkDevice device);
private: private:
vk::ShaderModule mLinkedVertexModule; vk::ShaderModule mLinkedVertexModule;
vk::ShaderModule mLinkedFragmentModule; vk::ShaderModule mLinkedFragmentModule;
vk::PipelineLayout mPipelineLayout;
}; };
} // namespace rx } // namespace rx
......
...@@ -49,6 +49,9 @@ constexpr Format::Format(GLenum internalFormat, ...@@ -49,6 +49,9 @@ constexpr Format::Format(GLenum internalFormat,
{ {
} }
// TODO(jmadill): This is temporary. Figure out how to handle format conversions.
VkFormat GetNativeVertexFormat(gl::VertexFormatType vertexFormat);
} // namespace vk } // namespace vk
} // namespace rx } // namespace rx
......
...@@ -366,6 +366,31 @@ void CommandBuffer::endRenderPass() ...@@ -366,6 +366,31 @@ void CommandBuffer::endRenderPass()
vkCmdEndRenderPass(mHandle); vkCmdEndRenderPass(mHandle);
} }
void CommandBuffer::draw(uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,
uint32_t firstInstance)
{
ASSERT(valid());
vkCmdDraw(mHandle, vertexCount, instanceCount, firstVertex, firstInstance);
}
void CommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint,
const vk::Pipeline &pipeline)
{
ASSERT(valid() && pipeline.valid());
vkCmdBindPipeline(mHandle, pipelineBindPoint, pipeline.getHandle());
}
void CommandBuffer::bindVertexBuffers(uint32_t firstBinding,
const std::vector<VkBuffer> &buffers,
const std::vector<VkDeviceSize> &offsets)
{
ASSERT(valid() && buffers.size() == offsets.size());
vkCmdBindVertexBuffers(mHandle, firstBinding, static_cast<uint32_t>(buffers.size()),
buffers.data(), offsets.data());
}
// Image implementation. // Image implementation.
Image::Image() : mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED) Image::Image() : mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED)
{ {
...@@ -412,6 +437,12 @@ void Image::changeLayoutTop(VkImageAspectFlags aspectMask, ...@@ -412,6 +437,12 @@ void Image::changeLayoutTop(VkImageAspectFlags aspectMask,
VkImageLayout newLayout, VkImageLayout newLayout,
CommandBuffer *commandBuffer) CommandBuffer *commandBuffer)
{ {
if (newLayout == mCurrentLayout)
{
// No-op.
return;
}
changeLayoutWithStages(aspectMask, newLayout, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, changeLayoutWithStages(aspectMask, newLayout, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, commandBuffer); VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, commandBuffer);
} }
...@@ -422,12 +453,6 @@ void Image::changeLayoutWithStages(VkImageAspectFlags aspectMask, ...@@ -422,12 +453,6 @@ void Image::changeLayoutWithStages(VkImageAspectFlags aspectMask,
VkPipelineStageFlags dstStageMask, VkPipelineStageFlags dstStageMask,
CommandBuffer *commandBuffer) CommandBuffer *commandBuffer)
{ {
if (newLayout == mCurrentLayout)
{
// No-op.
return;
}
VkImageMemoryBarrier imageMemoryBarrier; VkImageMemoryBarrier imageMemoryBarrier;
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.pNext = nullptr; imageMemoryBarrier.pNext = nullptr;
...@@ -842,6 +867,78 @@ Error ShaderModule::init(const VkShaderModuleCreateInfo &createInfo) ...@@ -842,6 +867,78 @@ Error ShaderModule::init(const VkShaderModuleCreateInfo &createInfo)
return NoError(); return NoError();
} }
// Pipeline implementation.
Pipeline::Pipeline()
{
}
Pipeline::Pipeline(VkDevice device) : WrappedObject(device)
{
}
Pipeline::Pipeline(Pipeline &&other) : WrappedObject(std::move(other))
{
}
Pipeline::~Pipeline()
{
if (mHandle)
{
ASSERT(validDevice());
vkDestroyPipeline(mDevice, mHandle, nullptr);
}
}
Pipeline &Pipeline::operator=(Pipeline &&other)
{
std::swap(mDevice, other.mDevice);
std::swap(mHandle, other.mHandle);
return *this;
}
Error Pipeline::initGraphics(const VkGraphicsPipelineCreateInfo &createInfo)
{
ASSERT(validDevice() && !valid());
ANGLE_VK_TRY(
vkCreateGraphicsPipelines(mDevice, VK_NULL_HANDLE, 1, &createInfo, nullptr, &mHandle));
return NoError();
}
// PipelineLayout implementation.
PipelineLayout::PipelineLayout()
{
}
PipelineLayout::PipelineLayout(VkDevice device) : WrappedObject(device)
{
}
PipelineLayout::PipelineLayout(PipelineLayout &&other) : WrappedObject(std::move(other))
{
}
PipelineLayout::~PipelineLayout()
{
if (mHandle != VK_NULL_HANDLE)
{
ASSERT(validDevice());
vkDestroyPipelineLayout(mDevice, mHandle, nullptr);
}
}
PipelineLayout &PipelineLayout::operator=(PipelineLayout &&other)
{
assignOpBase(std::move(other));
return *this;
}
Error PipelineLayout::init(const VkPipelineLayoutCreateInfo &createInfo)
{
ASSERT(validDevice() && !valid());
ANGLE_VK_TRY(vkCreatePipelineLayout(mDevice, &createInfo, nullptr, &mHandle));
return NoError();
}
} // namespace vk } // namespace vk
Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProps, Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProps,
...@@ -861,4 +958,69 @@ Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memory ...@@ -861,4 +958,69 @@ Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memory
return Optional<uint32_t>::Invalid(); return Optional<uint32_t>::Invalid();
} }
namespace gl_vk
{
VkPrimitiveTopology GetPrimitiveTopology(GLenum mode)
{
switch (mode)
{
case GL_TRIANGLES:
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
case GL_POINTS:
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
case GL_LINES:
return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
case GL_LINE_STRIP:
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
case GL_TRIANGLE_FAN:
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
case GL_TRIANGLE_STRIP:
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
case GL_LINE_LOOP:
// TODO(jmadill): Implement line loop support.
UNIMPLEMENTED();
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
default:
UNREACHABLE();
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
}
}
VkCullModeFlags GetCullMode(const gl::RasterizerState &rasterState)
{
if (!rasterState.cullFace)
{
return VK_CULL_MODE_NONE;
}
switch (rasterState.cullMode)
{
case GL_FRONT:
return VK_CULL_MODE_FRONT_BIT;
case GL_BACK:
return VK_CULL_MODE_BACK_BIT;
case GL_FRONT_AND_BACK:
return VK_CULL_MODE_FRONT_AND_BACK;
default:
UNREACHABLE();
return VK_CULL_MODE_NONE;
}
}
VkFrontFace GetFrontFace(GLenum frontFace)
{
switch (frontFace)
{
case GL_CW:
return VK_FRONT_FACE_CLOCKWISE;
case GL_CCW:
return VK_FRONT_FACE_COUNTER_CLOCKWISE;
default:
UNREACHABLE();
return VK_FRONT_FACE_COUNTER_CLOCKWISE;
}
}
} // namespace gl_vk
} // namespace rx } // namespace rx
...@@ -19,6 +19,7 @@ namespace gl ...@@ -19,6 +19,7 @@ namespace gl
{ {
struct Box; struct Box;
struct Extents; struct Extents;
struct RasterizerState;
struct Rectangle; struct Rectangle;
} }
...@@ -42,6 +43,7 @@ namespace vk ...@@ -42,6 +43,7 @@ namespace vk
class DeviceMemory; class DeviceMemory;
class Framebuffer; class Framebuffer;
class Image; class Image;
class Pipeline;
class RenderPass; class RenderPass;
class Error final class Error final
...@@ -141,6 +143,16 @@ class CommandBuffer final : public WrappedObject<VkCommandBuffer> ...@@ -141,6 +143,16 @@ class CommandBuffer final : public WrappedObject<VkCommandBuffer>
const std::vector<VkClearValue> &clearValues); const std::vector<VkClearValue> &clearValues);
void endRenderPass(); void endRenderPass();
void draw(uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,
uint32_t firstInstance);
void bindPipeline(VkPipelineBindPoint pipelineBindPoint, const vk::Pipeline &pipeline);
void bindVertexBuffers(uint32_t firstBinding,
const std::vector<VkBuffer> &buffers,
const std::vector<VkDeviceSize> &offsets);
private: private:
VkCommandPool mCommandPool; VkCommandPool mCommandPool;
}; };
...@@ -302,12 +314,43 @@ class ShaderModule final : public WrappedObject<VkShaderModule> ...@@ -302,12 +314,43 @@ class ShaderModule final : public WrappedObject<VkShaderModule>
Error init(const VkShaderModuleCreateInfo &createInfo); Error init(const VkShaderModuleCreateInfo &createInfo);
}; };
class Pipeline final : public WrappedObject<VkPipeline>
{
public:
Pipeline();
Pipeline(VkDevice device);
Pipeline(Pipeline &&other);
~Pipeline();
Pipeline &operator=(Pipeline &&other);
Error initGraphics(const VkGraphicsPipelineCreateInfo &createInfo);
};
class PipelineLayout final : public WrappedObject<VkPipelineLayout>
{
public:
PipelineLayout();
PipelineLayout(VkDevice device);
PipelineLayout(PipelineLayout &&other);
~PipelineLayout();
PipelineLayout &operator=(PipelineLayout &&other);
Error init(const VkPipelineLayoutCreateInfo &createInfo);
};
} // namespace vk } // namespace vk
Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProps, Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProps,
const VkMemoryRequirements &requirements, const VkMemoryRequirements &requirements,
uint32_t propertyFlagMask); uint32_t propertyFlagMask);
namespace gl_vk
{
VkPrimitiveTopology GetPrimitiveTopology(GLenum mode);
VkCullModeFlags GetCullMode(const gl::RasterizerState &rasterState);
VkFrontFace GetFrontFace(GLenum frontFace);
} // namespace gl_vk
} // namespace rx } // namespace rx
#define ANGLE_VK_TRY(command) \ #define ANGLE_VK_TRY(command) \
......
...@@ -236,6 +236,54 @@ TEST_P(SimpleOperationTest, BufferSubData) ...@@ -236,6 +236,54 @@ TEST_P(SimpleOperationTest, BufferSubData)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Simple quad test.
TEST_P(SimpleOperationTest, DrawQuad)
{
const std::string &vertexShader =
"attribute vec3 position;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 1);\n"
"}";
const std::string &fragmentShader =
"void main()\n"
"{\n"
" gl_FragColor = vec4(0, 1, 0, 1);\n"
"}";
ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
drawQuad(program.get(), "position", 0.5f, 1.0f, true);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Simple repeatd draw and swap test.
TEST_P(SimpleOperationTest, DrawQuadAndSwap)
{
const std::string &vertexShader =
"attribute vec3 position;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 1);\n"
"}";
const std::string &fragmentShader =
"void main()\n"
"{\n"
" gl_FragColor = vec4(0, 1, 0, 1);\n"
"}";
ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
for (int i = 0; i < 8; ++i)
{
drawQuad(program.get(), "position", 0.5f, 1.0f, true);
EXPECT_GL_NO_ERROR();
swapBuffers();
}
EXPECT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(SimpleOperationTest, ANGLE_INSTANTIATE_TEST(SimpleOperationTest,
ES2_D3D9(), ES2_D3D9(),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment