Commit 7b57b9d7 by Jamie Madill Committed by Commit Bot

Vulkan: Implement basic Clear and ReadPixels.

This enables the simple operations clear test on Vulkan. The current implementation is very synchronous - it will block and finish the current command buffer if there is any possibility of a race. BUG=angleproject:1319 Change-Id: If01fe9a19ed6f539639a38786193d3626164cada Reviewed-on: https://chromium-review.googlesource.com/367754 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent ac4e9c3f
...@@ -108,6 +108,16 @@ const FramebufferAttachment *FramebufferState::getReadAttachment() const ...@@ -108,6 +108,16 @@ const FramebufferAttachment *FramebufferState::getReadAttachment() const
return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr; return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
} }
const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
{
auto *colorAttachment = getFirstColorAttachment();
if (colorAttachment)
{
return colorAttachment;
}
return getDepthOrStencilAttachment();
}
const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
{ {
for (const FramebufferAttachment &colorAttachment : mColorAttachments) for (const FramebufferAttachment &colorAttachment : mColorAttachments)
......
...@@ -60,6 +60,7 @@ class FramebufferState final : angle::NonCopyable ...@@ -60,6 +60,7 @@ class FramebufferState final : angle::NonCopyable
const FramebufferAttachment *getAttachment(GLenum attachment) const; const FramebufferAttachment *getAttachment(GLenum attachment) const;
const FramebufferAttachment *getReadAttachment() const; const FramebufferAttachment *getReadAttachment() const;
const FramebufferAttachment *getFirstNonNullAttachment() const;
const FramebufferAttachment *getFirstColorAttachment() const; const FramebufferAttachment *getFirstColorAttachment() const;
const FramebufferAttachment *getDepthOrStencilAttachment() const; const FramebufferAttachment *getDepthOrStencilAttachment() const;
const FramebufferAttachment *getStencilOrDepthStencilAttachment() const; const FramebufferAttachment *getStencilOrDepthStencilAttachment() const;
......
...@@ -133,14 +133,15 @@ class FramebufferAttachment final ...@@ -133,14 +133,15 @@ class FramebufferAttachment final
{ {
static_assert(std::is_base_of<rx::FramebufferAttachmentRenderTarget, T>(), static_assert(std::is_base_of<rx::FramebufferAttachmentRenderTarget, T>(),
"Invalid RenderTarget class."); "Invalid RenderTarget class.");
return getRenderTarget(reinterpret_cast<rx::FramebufferAttachmentRenderTarget **>(rtOut)); return getRenderTargetImpl(
reinterpret_cast<rx::FramebufferAttachmentRenderTarget **>(rtOut));
} }
bool operator==(const FramebufferAttachment &other) const; bool operator==(const FramebufferAttachment &other) const;
bool operator!=(const FramebufferAttachment &other) const; bool operator!=(const FramebufferAttachment &other) const;
private: private:
gl::Error getRenderTarget(rx::FramebufferAttachmentRenderTarget **rtOut) const; gl::Error getRenderTargetImpl(rx::FramebufferAttachmentRenderTarget **rtOut) const;
GLenum mType; GLenum mType;
Target mTarget; Target mTarget;
...@@ -189,7 +190,8 @@ inline GLsizei FramebufferAttachment::getSamples() const ...@@ -189,7 +190,8 @@ inline GLsizei FramebufferAttachment::getSamples() const
return mResource->getAttachmentSamples(mTarget); return mResource->getAttachmentSamples(mTarget);
} }
inline gl::Error FramebufferAttachment::getRenderTarget(rx::FramebufferAttachmentRenderTarget **rtOut) const inline gl::Error FramebufferAttachment::getRenderTargetImpl(
rx::FramebufferAttachmentRenderTarget **rtOut) const
{ {
return mResource->getAttachmentRenderTarget(mTarget, rtOut); return mResource->getAttachmentRenderTarget(mTarget, rtOut);
} }
......
...@@ -113,11 +113,10 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer) ...@@ -113,11 +113,10 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
egl::Error result(EGL_NOT_INITIALIZED, "No available renderers.");
for (size_t i = 0; i < rendererCreationFunctions.size(); i++) for (size_t i = 0; i < rendererCreationFunctions.size(); i++)
{ {
RendererD3D *renderer = rendererCreationFunctions[i](display); RendererD3D *renderer = rendererCreationFunctions[i](display);
result = renderer->initialize(); egl::Error result = renderer->initialize();
# if defined(ANGLE_ENABLE_D3D11) # if defined(ANGLE_ENABLE_D3D11)
if (renderer->getRendererClass() == RENDERER_D3D11) if (renderer->getRendererClass() == RENDERER_D3D11)
...@@ -142,16 +141,14 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer) ...@@ -142,16 +141,14 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
if (!result.isError()) if (!result.isError())
{ {
*outRenderer = renderer; *outRenderer = renderer;
break; return result;
} }
else
{
// Failed to create the renderer, try the next // Failed to create the renderer, try the next
SafeDelete(renderer); SafeDelete(renderer);
} }
}
return result; return egl::Error(EGL_NOT_INITIALIZED, "No available renderers.");
} }
DisplayD3D::DisplayD3D(const egl::DisplayState &state) : DisplayImpl(state), mRenderer(nullptr) DisplayD3D::DisplayD3D(const egl::DisplayState &state) : DisplayImpl(state), mRenderer(nullptr)
......
...@@ -101,8 +101,24 @@ gl::Error ContextVk::drawRangeElements(GLenum mode, ...@@ -101,8 +101,24 @@ gl::Error ContextVk::drawRangeElements(GLenum mode,
const GLvoid *indices, const GLvoid *indices,
const gl::IndexRange &indexRange) const gl::IndexRange &indexRange)
{ {
UNIMPLEMENTED(); return gl::NoError();
return gl::Error(GL_INVALID_OPERATION); }
VkDevice ContextVk::getDevice() const
{
return mRenderer->getDevice();
}
vk::CommandBuffer *ContextVk::getCommandBuffer()
{
return mRenderer->getCommandBuffer();
}
vk::Error ContextVk::submitCommands(const vk::CommandBuffer &commandBuffer)
{
// TODO(jmadill): Command queuing.
ANGLE_TRY(mRenderer->submitAndFinishCommandBuffer(commandBuffer));
return vk::NoError();
} }
gl::Error ContextVk::drawArraysIndirect(GLenum mode, const GLvoid *indirect) gl::Error ContextVk::drawArraysIndirect(GLenum mode, const GLvoid *indirect)
...@@ -150,9 +166,9 @@ void ContextVk::popGroupMarker() ...@@ -150,9 +166,9 @@ void ContextVk::popGroupMarker()
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void ContextVk::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits) void ContextVk::syncState(const gl::State & /*state*/, const gl::State::DirtyBits & /*dirtyBits*/)
{ {
UNIMPLEMENTED(); // TODO(jmadill): Vulkan dirty bits.
} }
GLint ContextVk::getGPUDisjoint() GLint ContextVk::getGPUDisjoint()
...@@ -208,7 +224,7 @@ ProgramImpl *ContextVk::createProgram(const gl::ProgramState &state) ...@@ -208,7 +224,7 @@ ProgramImpl *ContextVk::createProgram(const gl::ProgramState &state)
FramebufferImpl *ContextVk::createFramebuffer(const gl::FramebufferState &state) FramebufferImpl *ContextVk::createFramebuffer(const gl::FramebufferState &state)
{ {
return new FramebufferVk(state); return FramebufferVk::CreateUserFBO(state);
} }
TextureImpl *ContextVk::createTexture(const gl::TextureState &state) TextureImpl *ContextVk::createTexture(const gl::TextureState &state)
......
...@@ -10,7 +10,10 @@ ...@@ -10,7 +10,10 @@
#ifndef LIBANGLE_RENDERER_VULKAN_CONTEXTVK_H_ #ifndef LIBANGLE_RENDERER_VULKAN_CONTEXTVK_H_
#define LIBANGLE_RENDERER_VULKAN_CONTEXTVK_H_ #define LIBANGLE_RENDERER_VULKAN_CONTEXTVK_H_
#include <vulkan/vulkan.h>
#include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
namespace rx namespace rx
{ {
...@@ -119,6 +122,12 @@ class ContextVk : public ContextImpl ...@@ -119,6 +122,12 @@ class ContextVk : public ContextImpl
// Path object creation // Path object creation
std::vector<PathImpl *> createPaths(GLsizei) override; std::vector<PathImpl *> createPaths(GLsizei) override;
VkDevice getDevice() const;
vk::CommandBuffer *getCommandBuffer();
vk::Error submitCommands(const vk::CommandBuffer &commandBuffer);
RendererVk *getRenderer() { return mRenderer; }
private: private:
RendererVk *mRenderer; RendererVk *mRenderer;
}; };
......
...@@ -9,15 +9,59 @@ ...@@ -9,15 +9,59 @@
#include "libANGLE/renderer/vulkan/FramebufferVk.h" #include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include <array>
#include <vulkan/vulkan.h>
#include "common/debug.h" #include "common/debug.h"
#include "image_util/imageformats.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/renderer_utils.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/SurfaceVk.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
namespace rx namespace rx
{ {
namespace
{
gl::ErrorOrResult<const gl::InternalFormat *> GetReadAttachmentInfo(
const gl::FramebufferAttachment *readAttachment)
{
RenderTargetVk *renderTarget = nullptr;
ANGLE_TRY(readAttachment->getRenderTarget(&renderTarget));
GLenum implFormat = renderTarget->format->format().fboImplementationInternalFormat;
return &gl::GetInternalFormatInfo(implFormat);
}
} // anonymous namespace
// static
FramebufferVk *FramebufferVk::CreateUserFBO(const gl::FramebufferState &state)
{
return new FramebufferVk(state);
}
// static
FramebufferVk *FramebufferVk::CreateDefaultFBO(const gl::FramebufferState &state,
WindowSurfaceVk *backbuffer)
{
return new FramebufferVk(state, backbuffer);
}
FramebufferVk::FramebufferVk(const gl::FramebufferState &state) : FramebufferImpl(state) FramebufferVk::FramebufferVk(const gl::FramebufferState &state) : FramebufferImpl(state)
{ {
} }
FramebufferVk::FramebufferVk(const gl::FramebufferState &state, WindowSurfaceVk *backbuffer)
: FramebufferImpl(state)
{
}
FramebufferVk::~FramebufferVk() FramebufferVk::~FramebufferVk()
{ {
} }
...@@ -44,8 +88,59 @@ gl::Error FramebufferVk::invalidateSub(size_t count, ...@@ -44,8 +88,59 @@ gl::Error FramebufferVk::invalidateSub(size_t count,
gl::Error FramebufferVk::clear(ContextImpl *context, GLbitfield mask) gl::Error FramebufferVk::clear(ContextImpl *context, GLbitfield mask)
{ {
ContextVk *contextVk = GetAs<ContextVk>(context);
if (mState.getDepthAttachment() && (mask & GL_DEPTH_BUFFER_BIT) != 0)
{
// TODO(jmadill): Depth clear
UNIMPLEMENTED(); UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION); }
if (mState.getStencilAttachment() && (mask & GL_STENCIL_BUFFER_BIT) != 0)
{
// TODO(jmadill): Stencil clear
UNIMPLEMENTED();
}
if ((mask & GL_COLOR_BUFFER_BIT) == 0)
{
return gl::NoError();
}
const auto &glState = context->getGLState();
const auto &clearColor = glState.getColorClearValue();
VkClearColorValue clearColorValue;
clearColorValue.float32[0] = clearColor.red;
clearColorValue.float32[1] = clearColor.green;
clearColorValue.float32[2] = clearColor.blue;
clearColorValue.float32[3] = clearColor.alpha;
// TODO(jmadill): Scissored clears.
const auto *attachment = mState.getFirstNonNullAttachment();
ASSERT(attachment && attachment->isAttached());
const auto &size = attachment->getSize();
const gl::Rectangle renderArea(0, 0, size.width, size.height);
vk::CommandBuffer *commandBuffer = contextVk->getCommandBuffer();
ANGLE_TRY(commandBuffer->begin());
for (const auto &colorAttachment : mState.getColorAttachments())
{
if (colorAttachment.isAttached())
{
RenderTargetVk *renderTarget = nullptr;
ANGLE_TRY(colorAttachment.getRenderTarget(&renderTarget));
renderTarget->image->changeLayoutTop(
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, commandBuffer);
commandBuffer->clearSingleColorImage(*renderTarget->image, clearColorValue);
}
}
commandBuffer->end();
ANGLE_TRY(contextVk->submitCommands(*commandBuffer));
return gl::NoError();
} }
gl::Error FramebufferVk::clearBufferfv(ContextImpl *context, gl::Error FramebufferVk::clearBufferfv(ContextImpl *context,
...@@ -87,14 +182,30 @@ gl::Error FramebufferVk::clearBufferfi(ContextImpl *context, ...@@ -87,14 +182,30 @@ gl::Error FramebufferVk::clearBufferfi(ContextImpl *context,
GLenum FramebufferVk::getImplementationColorReadFormat() const GLenum FramebufferVk::getImplementationColorReadFormat() const
{ {
UNIMPLEMENTED(); auto errOrResult = GetReadAttachmentInfo(mState.getReadAttachment());
return GLenum();
// TODO(jmadill): Handle getRenderTarget error.
if (errOrResult.isError())
{
ERR("Internal error in FramebufferVk::getImplementationColorReadFormat.");
return GL_NONE;
}
return errOrResult.getResult()->format;
} }
GLenum FramebufferVk::getImplementationColorReadType() const GLenum FramebufferVk::getImplementationColorReadType() const
{ {
UNIMPLEMENTED(); auto errOrResult = GetReadAttachmentInfo(mState.getReadAttachment());
return GLenum();
// TODO(jmadill): Handle getRenderTarget error.
if (errOrResult.isError())
{
ERR("Internal error in FramebufferVk::getImplementationColorReadFormat.");
return GL_NONE;
}
return errOrResult.getResult()->type;
} }
gl::Error FramebufferVk::readPixels(ContextImpl *context, gl::Error FramebufferVk::readPixels(ContextImpl *context,
...@@ -103,8 +214,65 @@ gl::Error FramebufferVk::readPixels(ContextImpl *context, ...@@ -103,8 +214,65 @@ gl::Error FramebufferVk::readPixels(ContextImpl *context,
GLenum type, GLenum type,
GLvoid *pixels) const GLvoid *pixels) const
{ {
UNIMPLEMENTED(); const auto &glState = context->getGLState();
return gl::Error(GL_INVALID_OPERATION); const auto *readFramebuffer = glState.getReadFramebuffer();
const auto *readAttachment = readFramebuffer->getReadColorbuffer();
RenderTargetVk *renderTarget = nullptr;
ANGLE_TRY(readAttachment->getRenderTarget(&renderTarget));
ContextVk *contextVk = GetAs<ContextVk>(context);
RendererVk *renderer = contextVk->getRenderer();
vk::Image *readImage = renderTarget->image;
vk::StagingImage stagingImage;
ANGLE_TRY_RESULT(renderer->createStagingImage(TextureDimension::TEX_2D, *renderTarget->format,
renderTarget->extents),
stagingImage);
vk::CommandBuffer *commandBuffer = contextVk->getCommandBuffer();
commandBuffer->begin();
stagingImage.getImage().changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL,
commandBuffer);
gl::Box copyRegion;
copyRegion.x = area.x;
copyRegion.y = area.y;
copyRegion.z = 0;
copyRegion.width = area.width;
copyRegion.height = area.height;
copyRegion.depth = 1;
readImage->changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
commandBuffer);
commandBuffer->copySingleImage(*readImage, stagingImage.getImage(), copyRegion,
VK_IMAGE_ASPECT_COLOR_BIT);
commandBuffer->end();
ANGLE_TRY(renderer->submitAndFinishCommandBuffer(*commandBuffer));
// TODO(jmadill): parameters
uint8_t *mapPointer = nullptr;
ANGLE_TRY(stagingImage.getDeviceMemory().map(0, stagingImage.getSize(), 0, &mapPointer));
const auto &angleFormat = renderTarget->format->format();
// TODO(jmadill): Use pixel bytes from the ANGLE format directly.
const auto &glFormat = gl::GetInternalFormatInfo(angleFormat.glInternalFormat);
int inputPitch = glFormat.pixelBytes * area.width;
PackPixelsParams params;
params.area = area;
params.format = format;
params.type = type;
params.outputPitch = inputPitch;
params.pack = glState.getPackState();
PackPixels(params, angleFormat, inputPitch, mapPointer, reinterpret_cast<uint8_t *>(pixels));
stagingImage.getDeviceMemory().unmap();
return vk::NoError();
} }
gl::Error FramebufferVk::blit(ContextImpl *context, gl::Error FramebufferVk::blit(ContextImpl *context,
...@@ -125,7 +293,7 @@ bool FramebufferVk::checkStatus() const ...@@ -125,7 +293,7 @@ bool FramebufferVk::checkStatus() const
void FramebufferVk::syncState(const gl::Framebuffer::DirtyBits &dirtyBits) void FramebufferVk::syncState(const gl::Framebuffer::DirtyBits &dirtyBits)
{ {
UNIMPLEMENTED(); // TODO(jmadill): Smarter update.
} }
} // namespace rx } // namespace rx
...@@ -11,14 +11,25 @@ ...@@ -11,14 +11,25 @@
#define LIBANGLE_RENDERER_VULKAN_FRAMEBUFFERVK_H_ #define LIBANGLE_RENDERER_VULKAN_FRAMEBUFFERVK_H_
#include "libANGLE/renderer/FramebufferImpl.h" #include "libANGLE/renderer/FramebufferImpl.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
namespace rx namespace rx
{ {
class RenderTargetVk;
class WindowSurfaceVk;
class FramebufferVk : public FramebufferImpl class FramebufferVk : public FramebufferImpl
{ {
public: public:
FramebufferVk(const gl::FramebufferState &state); // Factory methods so we don't have to use constructors with overloads.
static FramebufferVk *CreateUserFBO(const gl::FramebufferState &state);
// The passed-in SurfaceVK must be destroyed after this FBO is destroyed. Our Surface code is
// ref-counted on the number of 'current' contexts, so we shouldn't get any dangling surface
// references. See Surface::setIsCurrent(bool).
static FramebufferVk *CreateDefaultFBO(const gl::FramebufferState &state,
WindowSurfaceVk *backbuffer);
~FramebufferVk() override; ~FramebufferVk() override;
gl::Error discard(size_t count, const GLenum *attachments) override; gl::Error discard(size_t count, const GLenum *attachments) override;
...@@ -63,6 +74,10 @@ class FramebufferVk : public FramebufferImpl ...@@ -63,6 +74,10 @@ class FramebufferVk : public FramebufferImpl
bool checkStatus() const override; bool checkStatus() const override;
void syncState(const gl::Framebuffer::DirtyBits &dirtyBits) override; void syncState(const gl::Framebuffer::DirtyBits &dirtyBits) override;
private:
FramebufferVk(const gl::FramebufferState &state);
FramebufferVk(const gl::FramebufferState &state, WindowSurfaceVk *backbuffer);
}; };
} // namespace rx } // namespace rx
......
//
// 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.
//
// RenderTargetVk:
// Wrapper around a Vulkan renderable resource, using an ImageView.
//
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
namespace rx
{
RenderTargetVk::RenderTargetVk()
: format(nullptr), image(nullptr), imageView(nullptr), extents(), samples(VK_SAMPLE_COUNT_1_BIT)
{
}
} // namespace rx
//
// 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.
//
// RenderTargetVk:
// Wrapper around a Vulkan renderable resource, using an ImageView.
//
#ifndef LIBANGLE_RENDERER_VULKAN_RENDERTARGETVK_H_
#define LIBANGLE_RENDERER_VULKAN_RENDERTARGETVK_H_
#include <vulkan/vulkan.h>
#include "libANGLE/FramebufferAttachment.h"
namespace rx
{
namespace vk
{
struct Format;
class Image;
class ImageView;
}
// This is a very light-weight class that does not own to the resources it points to.
// It's meant only to copy across some information from a FramebufferAttachment to the
// business rendering logic.
class RenderTargetVk final : public FramebufferAttachmentRenderTarget
{
public:
RenderTargetVk();
const vk::Format *format;
vk::Image *image;
vk::ImageView *imageView;
gl::Extents extents;
VkSampleCountFlagBits samples;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_RENDERTARGETVK_H_
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "libANGLE/renderer/vulkan/FramebufferVk.h" #include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/TextureVk.h" #include "libANGLE/renderer/vulkan/TextureVk.h"
#include "libANGLE/renderer/vulkan/VertexArrayVk.h" #include "libANGLE/renderer/vulkan/VertexArrayVk.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
#include "platform/Platform.h" #include "platform/Platform.h"
namespace rx namespace rx
...@@ -90,7 +91,8 @@ RendererVk::RendererVk() ...@@ -90,7 +91,8 @@ RendererVk::RendererVk()
mQueue(VK_NULL_HANDLE), mQueue(VK_NULL_HANDLE),
mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()), mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
mDevice(VK_NULL_HANDLE), mDevice(VK_NULL_HANDLE),
mCommandPool(VK_NULL_HANDLE) mCommandPool(VK_NULL_HANDLE),
mHostVisibleMemoryIndex(std::numeric_limits<uint32_t>::max())
{ {
} }
...@@ -314,6 +316,22 @@ vk::Error RendererVk::initialize(const egl::AttributeMap &attribs) ...@@ -314,6 +316,22 @@ vk::Error RendererVk::initialize(const egl::AttributeMap &attribs)
ANGLE_TRY(initializeDevice(firstGraphicsQueueFamily)); ANGLE_TRY(initializeDevice(firstGraphicsQueueFamily));
} }
VkPhysicalDeviceMemoryProperties memoryProperties;
vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memoryProperties);
for (uint32_t memoryIndex = 0; memoryIndex < memoryProperties.memoryTypeCount; ++memoryIndex)
{
if ((memoryProperties.memoryTypes[memoryIndex].propertyFlags &
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
{
mHostVisibleMemoryIndex = memoryIndex;
break;
}
}
ANGLE_VK_CHECK(mHostVisibleMemoryIndex < std::numeric_limits<uint32_t>::max(),
VK_ERROR_INITIALIZATION_FAILED);
return vk::NoError(); return vk::NoError();
} }
...@@ -555,4 +573,44 @@ vk::Error RendererVk::submitAndFinishCommandBuffer(const vk::CommandBuffer &comm ...@@ -555,4 +573,44 @@ vk::Error RendererVk::submitAndFinishCommandBuffer(const vk::CommandBuffer &comm
return vk::NoError(); return vk::NoError();
} }
vk::Error RendererVk::waitThenFinishCommandBuffer(const vk::CommandBuffer &commandBuffer,
const vk::Semaphore &waitSemaphore)
{
VkCommandBuffer commandBufferHandle = commandBuffer.getHandle();
VkSemaphore waitHandle = waitSemaphore.getHandle();
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
VkSubmitInfo submitInfo;
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pNext = nullptr;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &waitHandle;
submitInfo.pWaitDstStageMask = &waitStageMask;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBufferHandle;
submitInfo.signalSemaphoreCount = 0;
submitInfo.pSignalSemaphores = nullptr;
// TODO(jmadill): Investigate how to properly queue command buffer work.
ANGLE_VK_TRY(vkQueueSubmit(mQueue, 1, &submitInfo, VK_NULL_HANDLE));
// Wait indefinitely for the queue to finish.
ANGLE_VK_TRY(vkQueueWaitIdle(mQueue));
return vk::NoError();
}
vk::ErrorOrResult<vk::StagingImage> RendererVk::createStagingImage(TextureDimension dimension,
const vk::Format &format,
const gl::Extents &extent)
{
ASSERT(mHostVisibleMemoryIndex != std::numeric_limits<uint32_t>::max());
vk::StagingImage stagingImage(mDevice);
ANGLE_TRY(stagingImage.init(mCurrentQueueFamilyIndex, mHostVisibleMemoryIndex, dimension,
format.native, extent));
return std::move(stagingImage);
}
} // namespace rx } // namespace rx
...@@ -25,6 +25,11 @@ class AttributeMap; ...@@ -25,6 +25,11 @@ class AttributeMap;
namespace rx namespace rx
{ {
namespace vk
{
struct Format;
}
class RendererVk : angle::NonCopyable class RendererVk : angle::NonCopyable
{ {
public: public:
...@@ -38,6 +43,7 @@ class RendererVk : angle::NonCopyable ...@@ -38,6 +43,7 @@ class RendererVk : angle::NonCopyable
VkInstance getInstance() const { return mInstance; } VkInstance getInstance() const { return mInstance; }
VkPhysicalDevice getPhysicalDevice() const { return mPhysicalDevice; } VkPhysicalDevice getPhysicalDevice() const { return mPhysicalDevice; }
VkQueue getQueue() const { return mQueue; }
VkDevice getDevice() const { return mDevice; } VkDevice getDevice() const { return mDevice; }
vk::ErrorOrResult<uint32_t> selectPresentQueueForSurface(VkSurfaceKHR surface); vk::ErrorOrResult<uint32_t> selectPresentQueueForSurface(VkSurfaceKHR surface);
...@@ -45,12 +51,18 @@ class RendererVk : angle::NonCopyable ...@@ -45,12 +51,18 @@ class RendererVk : angle::NonCopyable
// TODO(jmadill): Use ContextImpl for command buffers to enable threaded contexts. // TODO(jmadill): Use ContextImpl for command buffers to enable threaded contexts.
vk::CommandBuffer *getCommandBuffer(); vk::CommandBuffer *getCommandBuffer();
vk::Error submitAndFinishCommandBuffer(const vk::CommandBuffer &commandBuffer); vk::Error submitAndFinishCommandBuffer(const vk::CommandBuffer &commandBuffer);
vk::Error waitThenFinishCommandBuffer(const vk::CommandBuffer &commandBuffer,
const vk::Semaphore &waitSemaphore);
const gl::Caps &getNativeCaps() const; const gl::Caps &getNativeCaps() const;
const gl::TextureCapsMap &getNativeTextureCaps() const; const gl::TextureCapsMap &getNativeTextureCaps() const;
const gl::Extensions &getNativeExtensions() const; const gl::Extensions &getNativeExtensions() const;
const gl::Limitations &getNativeLimitations() const; const gl::Limitations &getNativeLimitations() const;
vk::ErrorOrResult<vk::StagingImage> createStagingImage(TextureDimension dimension,
const vk::Format &format,
const gl::Extents &extent);
private: private:
void ensureCapsInitialized() const; void ensureCapsInitialized() const;
void generateCaps(gl::Caps *outCaps, void generateCaps(gl::Caps *outCaps,
...@@ -77,6 +89,7 @@ class RendererVk : angle::NonCopyable ...@@ -77,6 +89,7 @@ class RendererVk : angle::NonCopyable
VkDevice mDevice; VkDevice mDevice;
VkCommandPool mCommandPool; VkCommandPool mCommandPool;
std::unique_ptr<vk::CommandBuffer> mCommandBuffer; std::unique_ptr<vk::CommandBuffer> mCommandBuffer;
uint32_t mHostVisibleMemoryIndex;
}; };
} // namespace rx } // namespace rx
......
...@@ -48,7 +48,8 @@ egl::Error OffscreenSurfaceVk::initialize(const DisplayImpl *displayImpl) ...@@ -48,7 +48,8 @@ egl::Error OffscreenSurfaceVk::initialize(const DisplayImpl *displayImpl)
FramebufferImpl *OffscreenSurfaceVk::createDefaultFramebuffer(const gl::FramebufferState &state) FramebufferImpl *OffscreenSurfaceVk::createDefaultFramebuffer(const gl::FramebufferState &state)
{ {
return new FramebufferVk(state); // Use a user FBO for an offscreen RT.
return FramebufferVk::CreateUserFBO(state);
} }
egl::Error OffscreenSurfaceVk::swap(const DisplayImpl *displayImpl) egl::Error OffscreenSurfaceVk::swap(const DisplayImpl *displayImpl)
...@@ -118,13 +119,16 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, ...@@ -118,13 +119,16 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState,
EGLint height) EGLint height)
: SurfaceImpl(surfaceState), : SurfaceImpl(surfaceState),
mNativeWindowType(window), mNativeWindowType(window),
mWidth(width),
mHeight(height),
mSurface(VK_NULL_HANDLE), mSurface(VK_NULL_HANDLE),
mSwapchain(VK_NULL_HANDLE), mSwapchain(VK_NULL_HANDLE),
mDevice(VK_NULL_HANDLE), mDevice(VK_NULL_HANDLE),
mInstance(VK_NULL_HANDLE) mInstance(VK_NULL_HANDLE),
mRenderTarget(),
mCurrentSwapchainImageIndex(0)
{ {
mRenderTarget.extents.width = static_cast<GLint>(width);
mRenderTarget.extents.height = static_cast<GLint>(height);
mRenderTarget.extents.depth = 1;
} }
WindowSurfaceVk::~WindowSurfaceVk() WindowSurfaceVk::~WindowSurfaceVk()
...@@ -176,29 +180,33 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer) ...@@ -176,29 +180,33 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, &surfaceCaps)); ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, &surfaceCaps));
// Adjust width and height to the swapchain if necessary. // Adjust width and height to the swapchain if necessary.
if (surfaceCaps.currentExtent.width != 0xFFFFFFFFu) uint32_t width = surfaceCaps.currentExtent.width;
{ uint32_t height = surfaceCaps.currentExtent.height;
ASSERT(surfaceCaps.currentExtent.height != 0xFFFFFFFFu);
mWidth = static_cast<EGLint>(surfaceCaps.currentExtent.width); // TODO(jmadill): Support devices which don't support copy. We use this for ReadPixels.
mHeight = static_cast<EGLint>(surfaceCaps.currentExtent.height); ANGLE_VK_CHECK((surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) != 0,
} VK_ERROR_INITIALIZATION_FAILED);
else
if (surfaceCaps.currentExtent.width == 0xFFFFFFFFu)
{ {
ASSERT(surfaceCaps.currentExtent.height == 0xFFFFFFFFu); ASSERT(surfaceCaps.currentExtent.height == 0xFFFFFFFFu);
RECT rect; RECT rect;
ANGLE_VK_CHECK(GetClientRect(mNativeWindowType, &rect) == TRUE, ANGLE_VK_CHECK(GetClientRect(mNativeWindowType, &rect) == TRUE,
VK_ERROR_INITIALIZATION_FAILED); VK_ERROR_INITIALIZATION_FAILED);
if (mWidth == 0) if (mRenderTarget.extents.width == 0)
{ {
mWidth = static_cast<EGLint>(rect.right - rect.left); width = static_cast<uint32_t>(rect.right - rect.left);
} }
if (mHeight == 0) if (mRenderTarget.extents.height == 0)
{ {
mHeight = static_cast<EGLint>(rect.bottom - rect.top); height = static_cast<uint32_t>(rect.bottom - rect.top);
} }
} }
mRenderTarget.extents.width = static_cast<int>(width);
mRenderTarget.extents.height = static_cast<int>(height);
uint32_t presentModeCount = 0; uint32_t presentModeCount = 0;
ANGLE_VK_TRY(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, mSurface, ANGLE_VK_TRY(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, mSurface,
&presentModeCount, nullptr)); &presentModeCount, nullptr));
...@@ -240,8 +248,6 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer) ...@@ -240,8 +248,6 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
preTransform = surfaceCaps.currentTransform; preTransform = surfaceCaps.currentTransform;
} }
const vk::Format &configSurfaceFormat = GetVkFormatFromConfig(*mState.config);
uint32_t surfaceFormatCount = 0; uint32_t surfaceFormatCount = 0;
ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface, &surfaceFormatCount, ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface, &surfaceFormatCount,
nullptr)); nullptr));
...@@ -250,6 +256,9 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer) ...@@ -250,6 +256,9 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface, &surfaceFormatCount, ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface, &surfaceFormatCount,
surfaceFormats.data())); surfaceFormats.data()));
mRenderTarget.format = &GetVkFormatFromConfig(*mState.config);
auto nativeFormat = mRenderTarget.format->native;
if (surfaceFormatCount == 1u && surfaceFormats[0].format == VK_FORMAT_UNDEFINED) if (surfaceFormatCount == 1u && surfaceFormats[0].format == VK_FORMAT_UNDEFINED)
{ {
// This is fine. // This is fine.
...@@ -259,7 +268,7 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer) ...@@ -259,7 +268,7 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
bool foundFormat = false; bool foundFormat = false;
for (const auto &surfaceFormat : surfaceFormats) for (const auto &surfaceFormat : surfaceFormats)
{ {
if (surfaceFormat.format == configSurfaceFormat.native) if (surfaceFormat.format == nativeFormat)
{ {
foundFormat = true; foundFormat = true;
break; break;
...@@ -275,12 +284,13 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer) ...@@ -275,12 +284,13 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
swapchainInfo.flags = 0; swapchainInfo.flags = 0;
swapchainInfo.surface = mSurface; swapchainInfo.surface = mSurface;
swapchainInfo.minImageCount = minImageCount; swapchainInfo.minImageCount = minImageCount;
swapchainInfo.imageFormat = configSurfaceFormat.native; swapchainInfo.imageFormat = nativeFormat;
swapchainInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; swapchainInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
swapchainInfo.imageExtent.width = mWidth; swapchainInfo.imageExtent.width = width;
swapchainInfo.imageExtent.height = mHeight; swapchainInfo.imageExtent.height = height;
swapchainInfo.imageArrayLayers = 1; swapchainInfo.imageArrayLayers = 1;
swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchainInfo.imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapchainInfo.queueFamilyIndexCount = 0; swapchainInfo.queueFamilyIndexCount = 0;
swapchainInfo.pQueueFamilyIndices = nullptr; swapchainInfo.pQueueFamilyIndices = nullptr;
...@@ -304,6 +314,12 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer) ...@@ -304,6 +314,12 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
vk::CommandBuffer *commandBuffer = renderer->getCommandBuffer(); vk::CommandBuffer *commandBuffer = renderer->getCommandBuffer();
ANGLE_TRY(commandBuffer->begin()); ANGLE_TRY(commandBuffer->begin());
VkClearColorValue transparentBlack;
transparentBlack.float32[0] = 0.0f;
transparentBlack.float32[1] = 0.0f;
transparentBlack.float32[2] = 0.0f;
transparentBlack.float32[3] = 0.0f;
for (auto swapchainImage : swapchainImages) for (auto swapchainImage : swapchainImages)
{ {
VkImageViewCreateInfo imageViewInfo; VkImageViewCreateInfo imageViewInfo;
...@@ -312,7 +328,7 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer) ...@@ -312,7 +328,7 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
imageViewInfo.flags = 0; imageViewInfo.flags = 0;
imageViewInfo.image = swapchainImage; imageViewInfo.image = swapchainImage;
imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewInfo.format = configSurfaceFormat.native; imageViewInfo.format = nativeFormat;
imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_R; imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_G; imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_B; imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
...@@ -327,9 +343,10 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer) ...@@ -327,9 +343,10 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
vk::ImageView imageView(device); vk::ImageView imageView(device);
ANGLE_TRY(imageView.init(imageViewInfo)); ANGLE_TRY(imageView.init(imageViewInfo));
// Set optimal color layout for the image. // Set transfer dest layout, and clear the image to black.
image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, image.changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
commandBuffer); commandBuffer);
commandBuffer->clearSingleColorImage(image, transparentBlack);
mSwapchainImages.push_back(std::move(image)); mSwapchainImages.push_back(std::move(image));
mSwapchainImageViews.push_back(std::move(imageView)); mSwapchainImageViews.push_back(std::move(imageView));
...@@ -338,18 +355,73 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer) ...@@ -338,18 +355,73 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
ANGLE_TRY(commandBuffer->end()); ANGLE_TRY(commandBuffer->end());
ANGLE_TRY(renderer->submitAndFinishCommandBuffer(*commandBuffer)); ANGLE_TRY(renderer->submitAndFinishCommandBuffer(*commandBuffer));
// Start by getting the next available swapchain image.
ANGLE_TRY(nextSwapchainImage(renderer));
return vk::NoError(); return vk::NoError();
} }
FramebufferImpl *WindowSurfaceVk::createDefaultFramebuffer(const gl::FramebufferState &state) FramebufferImpl *WindowSurfaceVk::createDefaultFramebuffer(const gl::FramebufferState &state)
{ {
return new FramebufferVk(state); return FramebufferVk::CreateDefaultFBO(state, this);
} }
egl::Error WindowSurfaceVk::swap(const DisplayImpl *displayImpl) egl::Error WindowSurfaceVk::swap(const DisplayImpl *displayImpl)
{ {
// TODO(jmadill) const DisplayVk *displayVk = GetAs<DisplayVk>(displayImpl);
return egl::Error(EGL_SUCCESS); return swapImpl(displayVk->getRenderer()).toEGL(EGL_BAD_ALLOC);
}
vk::Error WindowSurfaceVk::swapImpl(RendererVk *renderer)
{
vk::CommandBuffer *currentCB = renderer->getCommandBuffer();
auto *image = &mSwapchainImages[mCurrentSwapchainImageIndex];
currentCB->begin();
image->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, currentCB);
currentCB->end();
ANGLE_TRY(renderer->waitThenFinishCommandBuffer(*currentCB, mPresentCompleteSemaphore));
VkPresentInfoKHR presentInfo;
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.pNext = nullptr;
presentInfo.waitSemaphoreCount = 0;
presentInfo.pWaitSemaphores = nullptr;
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &mSwapchain;
presentInfo.pImageIndices = &mCurrentSwapchainImageIndex;
presentInfo.pResults = nullptr;
ANGLE_VK_TRY(vkQueuePresentKHR(renderer->getQueue(), &presentInfo));
// Get the next available swapchain iamge.
ANGLE_TRY(nextSwapchainImage(renderer));
return vk::NoError();
}
vk::Error WindowSurfaceVk::nextSwapchainImage(RendererVk *renderer)
{
VkDevice device = renderer->getDevice();
vk::Semaphore presentComplete(device);
ANGLE_TRY(presentComplete.init());
ANGLE_VK_TRY(vkAcquireNextImageKHR(device, mSwapchain, std::numeric_limits<uint64_t>::max(),
presentComplete.getHandle(), VK_NULL_HANDLE,
&mCurrentSwapchainImageIndex));
mPresentCompleteSemaphore = std::move(presentComplete);
// Update RenderTarget pointers.
mRenderTarget.image = &mSwapchainImages[mCurrentSwapchainImageIndex];
mRenderTarget.imageView = &mSwapchainImageViews[mCurrentSwapchainImageIndex];
return vk::NoError();
} }
egl::Error WindowSurfaceVk::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) egl::Error WindowSurfaceVk::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height)
...@@ -380,12 +452,12 @@ void WindowSurfaceVk::setSwapInterval(EGLint interval) ...@@ -380,12 +452,12 @@ void WindowSurfaceVk::setSwapInterval(EGLint interval)
EGLint WindowSurfaceVk::getWidth() const EGLint WindowSurfaceVk::getWidth() const
{ {
return mWidth; return static_cast<EGLint>(mRenderTarget.extents.width);
} }
EGLint WindowSurfaceVk::getHeight() const EGLint WindowSurfaceVk::getHeight() const
{ {
return mHeight; return static_cast<EGLint>(mRenderTarget.extents.height);
} }
EGLint WindowSurfaceVk::isPostSubBufferSupported() const EGLint WindowSurfaceVk::isPostSubBufferSupported() const
...@@ -401,11 +473,11 @@ EGLint WindowSurfaceVk::getSwapBehavior() const ...@@ -401,11 +473,11 @@ EGLint WindowSurfaceVk::getSwapBehavior() const
} }
gl::Error WindowSurfaceVk::getAttachmentRenderTarget( gl::Error WindowSurfaceVk::getAttachmentRenderTarget(
const gl::FramebufferAttachment::Target &target, const gl::FramebufferAttachment::Target & /*target*/,
FramebufferAttachmentRenderTarget **rtOut) FramebufferAttachmentRenderTarget **rtOut)
{ {
UNREACHABLE(); *rtOut = &mRenderTarget;
return gl::Error(GL_INVALID_OPERATION); return gl::NoError();
} }
} // namespace rx } // namespace rx
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include "libANGLE/renderer/SurfaceImpl.h" #include "libANGLE/renderer/SurfaceImpl.h"
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h" #include "libANGLE/renderer/vulkan/renderervk_utils.h"
namespace rx namespace rx
...@@ -83,8 +84,6 @@ class WindowSurfaceVk : public SurfaceImpl ...@@ -83,8 +84,6 @@ class WindowSurfaceVk : public SurfaceImpl
vk::Error swapImpl(RendererVk *renderer); vk::Error swapImpl(RendererVk *renderer);
EGLNativeWindowType mNativeWindowType; EGLNativeWindowType mNativeWindowType;
EGLint mWidth;
EGLint mHeight;
VkSurfaceKHR mSurface; VkSurfaceKHR mSurface;
VkSwapchainKHR mSwapchain; VkSwapchainKHR mSwapchain;
// These are needed for resource deallocation. // These are needed for resource deallocation.
...@@ -92,6 +91,10 @@ class WindowSurfaceVk : public SurfaceImpl ...@@ -92,6 +91,10 @@ class WindowSurfaceVk : public SurfaceImpl
VkDevice mDevice; VkDevice mDevice;
VkInstance mInstance; VkInstance mInstance;
RenderTargetVk mRenderTarget;
vk::Semaphore mPresentCompleteSemaphore;
uint32_t mCurrentSwapchainImageIndex;
std::vector<vk::Image> mSwapchainImages; std::vector<vk::Image> mSwapchainImages;
std::vector<vk::ImageView> mSwapchainImageViews; std::vector<vk::ImageView> mSwapchainImageViews;
}; };
......
...@@ -62,6 +62,7 @@ VkAccessFlags GetBasicLayoutAccessFlags(VkImageLayout layout) ...@@ -62,6 +62,7 @@ VkAccessFlags GetBasicLayoutAccessFlags(VkImageLayout layout)
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
return VK_ACCESS_TRANSFER_READ_BIT; return VK_ACCESS_TRANSFER_READ_BIT;
case VK_IMAGE_LAYOUT_UNDEFINED: case VK_IMAGE_LAYOUT_UNDEFINED:
case VK_IMAGE_LAYOUT_GENERAL:
return 0; return 0;
default: default:
// TODO(jmadill): Investigate other flags. // TODO(jmadill): Investigate other flags.
...@@ -136,6 +137,19 @@ const char *VulkanResultString(VkResult result) ...@@ -136,6 +137,19 @@ const char *VulkanResultString(VkResult result)
} }
} }
bool HasStandardValidationLayer(const std::vector<VkLayerProperties> &layerProps)
{
for (const auto &layerProp : layerProps)
{
if (std::string(layerProp.layerName) == g_VkStdValidationLayerName)
{
return true;
}
}
return false;
}
namespace vk namespace vk
{ {
...@@ -273,11 +287,65 @@ CommandBuffer::~CommandBuffer() ...@@ -273,11 +287,65 @@ CommandBuffer::~CommandBuffer()
} }
} }
void CommandBuffer::clearSingleColorImage(const vk::Image &image, const VkClearColorValue &color)
{
ASSERT(valid());
ASSERT(image.getCurrentLayout() == VK_IMAGE_LAYOUT_GENERAL ||
image.getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkImageSubresourceRange range;
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
range.baseMipLevel = 0;
range.levelCount = 1;
range.baseArrayLayer = 0;
range.layerCount = 1;
vkCmdClearColorImage(mHandle, image.getHandle(), image.getCurrentLayout(), &color, 1, &range);
}
void CommandBuffer::copySingleImage(const vk::Image &srcImage,
const vk::Image &destImage,
const gl::Box &copyRegion,
VkImageAspectFlags aspectMask)
{
ASSERT(valid());
ASSERT(srcImage.getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ||
srcImage.getCurrentLayout() == VK_IMAGE_LAYOUT_GENERAL);
ASSERT(destImage.getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ||
destImage.getCurrentLayout() == VK_IMAGE_LAYOUT_GENERAL);
VkImageCopy region;
region.srcSubresource.aspectMask = aspectMask;
region.srcSubresource.mipLevel = 0;
region.srcSubresource.baseArrayLayer = 0;
region.srcSubresource.layerCount = 1;
region.srcOffset.x = copyRegion.x;
region.srcOffset.y = copyRegion.y;
region.srcOffset.z = copyRegion.z;
region.dstSubresource.aspectMask = aspectMask;
region.dstSubresource.mipLevel = 0;
region.dstSubresource.baseArrayLayer = 0;
region.dstSubresource.layerCount = 1;
region.dstOffset.x = copyRegion.x;
region.dstOffset.y = copyRegion.y;
region.dstOffset.z = copyRegion.z;
region.extent.width = copyRegion.width;
region.extent.height = copyRegion.height;
region.extent.depth = copyRegion.depth;
vkCmdCopyImage(mHandle, srcImage.getHandle(), srcImage.getCurrentLayout(),
destImage.getHandle(), destImage.getCurrentLayout(), 1, &region);
}
// Image implementation. // Image implementation.
Image::Image() : mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED) Image::Image() : mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED)
{ {
} }
Image::Image(VkDevice device) : WrappedObject(device), mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED)
{
}
Image::Image(VkImage image) : mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED) Image::Image(VkImage image) : mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED)
{ {
mHandle = image; mHandle = image;
...@@ -304,10 +372,27 @@ Image::~Image() ...@@ -304,10 +372,27 @@ Image::~Image()
} }
} }
void Image::changeLayout(VkImageAspectFlags aspectMask, Error Image::init(const VkImageCreateInfo &createInfo)
{
ASSERT(mHandle == VK_NULL_HANDLE && validDevice());
ANGLE_VK_TRY(vkCreateImage(mDevice, &createInfo, nullptr, &mHandle));
return NoError();
}
void Image::changeLayoutTop(VkImageAspectFlags aspectMask,
VkImageLayout newLayout, VkImageLayout newLayout,
CommandBuffer *commandBuffer) CommandBuffer *commandBuffer)
{ {
changeLayoutWithStages(aspectMask, newLayout, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, commandBuffer);
}
void Image::changeLayoutWithStages(VkImageAspectFlags aspectMask,
VkImageLayout newLayout,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
CommandBuffer *commandBuffer)
{
if (newLayout == mCurrentLayout) if (newLayout == mCurrentLayout)
{ {
// No-op. // No-op.
...@@ -354,12 +439,24 @@ void Image::changeLayout(VkImageAspectFlags aspectMask, ...@@ -354,12 +439,24 @@ void Image::changeLayout(VkImageAspectFlags aspectMask,
imageMemoryBarrier.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; imageMemoryBarrier.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
} }
commandBuffer->singleImageBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, commandBuffer->singleImageBarrier(srcStageMask, dstStageMask, 0, imageMemoryBarrier);
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, imageMemoryBarrier);
mCurrentLayout = newLayout; mCurrentLayout = newLayout;
} }
void Image::getMemoryRequirements(VkMemoryRequirements *requirementsOut) const
{
ASSERT(valid());
vkGetImageMemoryRequirements(mDevice, mHandle, requirementsOut);
}
Error Image::bindMemory(const vk::DeviceMemory &deviceMemory)
{
ASSERT(valid() && deviceMemory.valid());
ANGLE_VK_TRY(vkBindImageMemory(mDevice, mHandle, deviceMemory.getHandle(), 0));
return NoError();
}
// ImageView implementation. // ImageView implementation.
ImageView::ImageView() ImageView::ImageView()
{ {
...@@ -395,19 +492,213 @@ Error ImageView::init(const VkImageViewCreateInfo &createInfo) ...@@ -395,19 +492,213 @@ Error ImageView::init(const VkImageViewCreateInfo &createInfo)
return NoError(); return NoError();
} }
} // namespace vk // Semaphore implementation.
Semaphore::Semaphore()
{
}
bool HasStandardValidationLayer(const std::vector<VkLayerProperties> &layerProps) Semaphore::Semaphore(VkDevice device) : WrappedObject(device)
{ {
for (const auto &layerProp : layerProps) }
Semaphore::Semaphore(Semaphore &&other) : WrappedObject(std::move(other))
{
}
Semaphore::~Semaphore()
{
if (mHandle != VK_NULL_HANDLE)
{ {
if (std::string(layerProp.layerName) == g_VkStdValidationLayerName) ASSERT(validDevice());
vkDestroySemaphore(mDevice, mHandle, nullptr);
}
}
Semaphore &Semaphore::operator=(Semaphore &&other)
{
assignOpBase(std::move(other));
return *this;
}
Error Semaphore::init()
{
ASSERT(validDevice() && !valid());
VkSemaphoreCreateInfo semaphoreInfo;
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphoreInfo.pNext = nullptr;
semaphoreInfo.flags = 0;
ANGLE_VK_TRY(vkCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &mHandle));
return NoError();
}
// Framebuffer implementation.
Framebuffer::Framebuffer()
{
}
Framebuffer::Framebuffer(VkDevice device) : WrappedObject(device)
{
}
Framebuffer::Framebuffer(Framebuffer &&other) : WrappedObject(std::move(other))
{
}
Framebuffer::~Framebuffer()
{
if (mHandle != VK_NULL_HANDLE)
{ {
return true; ASSERT(validDevice());
vkDestroyFramebuffer(mDevice, mHandle, nullptr);
} }
}
Framebuffer &Framebuffer::operator=(Framebuffer &&other)
{
assignOpBase(std::move(other));
return *this;
}
Error Framebuffer::init(const VkFramebufferCreateInfo &createInfo)
{
ASSERT(validDevice() && !valid());
ANGLE_VK_TRY(vkCreateFramebuffer(mDevice, &createInfo, nullptr, &mHandle));
return NoError();
}
// DeviceMemory implementation.
DeviceMemory::DeviceMemory()
{
}
DeviceMemory::DeviceMemory(VkDevice device) : WrappedObject(device)
{
}
DeviceMemory::DeviceMemory(DeviceMemory &&other) : WrappedObject(std::move(other))
{
}
DeviceMemory::~DeviceMemory()
{
if (mHandle != VK_NULL_HANDLE)
{
ASSERT(validDevice());
vkFreeMemory(mDevice, mHandle, nullptr);
} }
}
return false; DeviceMemory &DeviceMemory::operator=(DeviceMemory &&other)
{
assignOpBase(std::move(other));
return *this;
}
Error DeviceMemory::allocate(const VkMemoryAllocateInfo &allocInfo)
{
ASSERT(validDevice() && !valid());
ANGLE_VK_TRY(vkAllocateMemory(mDevice, &allocInfo, nullptr, &mHandle));
return NoError();
} }
Error DeviceMemory::map(VkDeviceSize offset,
VkDeviceSize size,
VkMemoryMapFlags flags,
uint8_t **mapPointer)
{
ASSERT(valid());
ANGLE_VK_TRY(
vkMapMemory(mDevice, mHandle, offset, size, flags, reinterpret_cast<void **>(mapPointer)));
return NoError();
}
void DeviceMemory::unmap()
{
ASSERT(valid());
vkUnmapMemory(mDevice, mHandle);
}
// StagingImage implementation.
StagingImage::StagingImage() : mSize(0)
{
}
StagingImage::StagingImage(VkDevice device) : mImage(device), mDeviceMemory(device), mSize(0)
{
}
StagingImage::StagingImage(StagingImage &&other)
: mImage(std::move(other.mImage)),
mDeviceMemory(std::move(other.mDeviceMemory)),
mSize(other.mSize)
{
other.mSize = 0;
}
StagingImage::~StagingImage()
{
}
StagingImage &StagingImage::operator=(StagingImage &&other)
{
std::swap(mImage, other.mImage);
std::swap(mDeviceMemory, other.mDeviceMemory);
std::swap(mSize, other.mSize);
return *this;
}
Error StagingImage::init(uint32_t queueFamilyIndex,
uint32_t hostVisibleMemoryIndex,
TextureDimension dimension,
VkFormat format,
const gl::Extents &extent)
{
VkImageCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.imageType = VK_IMAGE_TYPE_2D;
createInfo.format = format;
createInfo.extent.width = static_cast<uint32_t>(extent.width);
createInfo.extent.height = static_cast<uint32_t>(extent.height);
createInfo.extent.depth = static_cast<uint32_t>(extent.depth);
createInfo.mipLevels = 1;
createInfo.arrayLayers = 1;
createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
createInfo.tiling = VK_IMAGE_TILING_LINEAR;
createInfo.usage = (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 1;
createInfo.pQueueFamilyIndices = &queueFamilyIndex;
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
ANGLE_TRY(mImage.init(createInfo));
VkMemoryRequirements memoryRequirements;
mImage.getMemoryRequirements(&memoryRequirements);
// Ensure we can read this memory.
ANGLE_VK_CHECK((memoryRequirements.memoryTypeBits & (1 << hostVisibleMemoryIndex)) != 0,
VK_ERROR_VALIDATION_FAILED_EXT);
VkMemoryAllocateInfo allocateInfo;
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocateInfo.pNext = nullptr;
allocateInfo.allocationSize = memoryRequirements.size;
allocateInfo.memoryTypeIndex = hostVisibleMemoryIndex;
ANGLE_TRY(mDeviceMemory.allocate(allocateInfo));
ANGLE_TRY(mImage.bindMemory(mDeviceMemory));
mSize = memoryRequirements.size;
return NoError();
}
} // namespace vk
} // namespace rx } // namespace rx
...@@ -14,16 +14,33 @@ ...@@ -14,16 +14,33 @@
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
namespace rx namespace gl
{ {
struct Box;
struct Extents;
struct Rectangle;
}
namespace rx
{
const char *VulkanResultString(VkResult result); const char *VulkanResultString(VkResult result);
bool HasStandardValidationLayer(const std::vector<VkLayerProperties> &layerProps); bool HasStandardValidationLayer(const std::vector<VkLayerProperties> &layerProps);
extern const char *g_VkStdValidationLayerName; extern const char *g_VkStdValidationLayerName;
enum class TextureDimension
{
TEX_2D,
TEX_CUBE,
TEX_3D,
TEX_2D_ARRAY,
};
namespace vk namespace vk
{ {
class DeviceMemory;
class Framebuffer;
class Image;
class Error final class Error final
{ {
...@@ -103,6 +120,13 @@ class CommandBuffer final : public WrappedObject<VkCommandBuffer> ...@@ -103,6 +120,13 @@ class CommandBuffer final : public WrappedObject<VkCommandBuffer>
VkDependencyFlags dependencyFlags, VkDependencyFlags dependencyFlags,
const VkImageMemoryBarrier &imageMemoryBarrier); const VkImageMemoryBarrier &imageMemoryBarrier);
void clearSingleColorImage(const vk::Image &image, const VkClearColorValue &color);
void copySingleImage(const vk::Image &srcImage,
const vk::Image &destImage,
const gl::Box &copyRegion,
VkImageAspectFlags aspectMask);
private: private:
VkCommandPool mCommandPool; VkCommandPool mCommandPool;
}; };
...@@ -112,6 +136,7 @@ class Image final : public WrappedObject<VkImage> ...@@ -112,6 +136,7 @@ class Image final : public WrappedObject<VkImage>
public: public:
// Use this constructor if the lifetime of the image is not controlled by ANGLE. (SwapChain) // Use this constructor if the lifetime of the image is not controlled by ANGLE. (SwapChain)
Image(); Image();
Image(VkDevice device);
explicit Image(VkImage image); explicit Image(VkImage image);
Image(Image &&other); Image(Image &&other);
...@@ -119,10 +144,23 @@ class Image final : public WrappedObject<VkImage> ...@@ -119,10 +144,23 @@ class Image final : public WrappedObject<VkImage>
~Image() override; ~Image() override;
void changeLayout(VkImageAspectFlags aspectMask, Error init(const VkImageCreateInfo &createInfo);
void changeLayoutTop(VkImageAspectFlags aspectMask,
VkImageLayout newLayout, VkImageLayout newLayout,
CommandBuffer *commandBuffer); CommandBuffer *commandBuffer);
void changeLayoutWithStages(VkImageAspectFlags aspectMask,
VkImageLayout newLayout,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
CommandBuffer *commandBuffer);
void getMemoryRequirements(VkMemoryRequirements *requirementsOut) const;
Error bindMemory(const vk::DeviceMemory &deviceMemory);
VkImageLayout getCurrentLayout() const { return mCurrentLayout; }
private: private:
VkImageLayout mCurrentLayout; VkImageLayout mCurrentLayout;
}; };
...@@ -141,6 +179,71 @@ class ImageView final : public WrappedObject<VkImageView> ...@@ -141,6 +179,71 @@ class ImageView final : public WrappedObject<VkImageView>
Error init(const VkImageViewCreateInfo &createInfo); Error init(const VkImageViewCreateInfo &createInfo);
}; };
class Semaphore final : public WrappedObject<VkSemaphore>
{
public:
Semaphore();
Semaphore(VkDevice device);
Semaphore(Semaphore &&other);
~Semaphore();
Semaphore &operator=(Semaphore &&other);
Error init();
};
class Framebuffer final : public WrappedObject<VkFramebuffer>
{
public:
Framebuffer();
Framebuffer(VkDevice device);
Framebuffer(Framebuffer &&other);
~Framebuffer();
Framebuffer &operator=(Framebuffer &&other);
Error init(const VkFramebufferCreateInfo &createInfo);
};
class DeviceMemory final : public WrappedObject<VkDeviceMemory>
{
public:
DeviceMemory();
DeviceMemory(VkDevice device);
DeviceMemory(DeviceMemory &&other);
~DeviceMemory();
DeviceMemory &operator=(DeviceMemory &&other);
Error allocate(const VkMemoryAllocateInfo &allocInfo);
Error map(VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, uint8_t **mapPointer);
void unmap();
};
class StagingImage final : angle::NonCopyable
{
public:
StagingImage();
StagingImage(VkDevice device);
StagingImage(StagingImage &&other);
~StagingImage();
StagingImage &operator=(StagingImage &&other);
vk::Error init(uint32_t queueFamilyIndex,
uint32_t hostVisibleMemoryIndex,
TextureDimension dimension,
VkFormat format,
const gl::Extents &extent);
Image &getImage() { return mImage; }
const Image &getImage() const { return mImage; }
DeviceMemory &getDeviceMemory() { return mDeviceMemory; }
const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; }
VkDeviceSize getSize() const { return mSize; }
private:
Image mImage;
DeviceMemory mDeviceMemory;
VkDeviceSize mSize;
};
} // namespace vk } // namespace vk
} // namespace rx } // namespace rx
......
...@@ -631,6 +631,8 @@ ...@@ -631,6 +631,8 @@
'libANGLE/renderer/vulkan/RenderbufferVk.h', 'libANGLE/renderer/vulkan/RenderbufferVk.h',
'libANGLE/renderer/vulkan/RendererVk.cpp', 'libANGLE/renderer/vulkan/RendererVk.cpp',
'libANGLE/renderer/vulkan/RendererVk.h', 'libANGLE/renderer/vulkan/RendererVk.h',
'libANGLE/renderer/vulkan/RenderTargetVk.cpp',
'libANGLE/renderer/vulkan/RenderTargetVk.h',
'libANGLE/renderer/vulkan/SamplerVk.cpp', 'libANGLE/renderer/vulkan/SamplerVk.cpp',
'libANGLE/renderer/vulkan/SamplerVk.h', 'libANGLE/renderer/vulkan/SamplerVk.h',
'libANGLE/renderer/vulkan/ShaderVk.cpp', 'libANGLE/renderer/vulkan/ShaderVk.cpp',
......
...@@ -145,16 +145,11 @@ TEST_P(RendererTest, SimpleOperation) ...@@ -145,16 +145,11 @@ TEST_P(RendererTest, SimpleOperation)
return; return;
} }
// TODO(jmadil): Vulkan clear.
if (IsVulkan())
{
std::cout << "Vulkan clears not yet implemented" << std::endl;
return;
}
glClearColor(0.0f, 1.0f, 0.0f, 1.0f); glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255); EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
ASSERT_GL_NO_ERROR();
} }
// Select configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Select configurations (e.g. which renderer, which GLES major version) these tests should be run against.
......
...@@ -270,6 +270,12 @@ void ANGLETest::TearDown() ...@@ -270,6 +270,12 @@ void ANGLETest::TearDown()
angle::WriteDebugMessage("Exiting %s.%s\n", info->test_case_name(), info->name()); angle::WriteDebugMessage("Exiting %s.%s\n", info->test_case_name(), info->name());
swapBuffers(); swapBuffers();
if (eglGetError() != EGL_SUCCESS)
{
FAIL() << "egl error during swap.";
}
mOSWindow->messageLoop(); mOSWindow->messageLoop();
if (!destroyEGLContext()) if (!destroyEGLContext())
......
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