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
SafeDelete(renderer);
} }
// Failed to create the renderer, try the next
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)
{ {
UNIMPLEMENTED(); ContextVk *contextVk = GetAs<ContextVk>(context);
return gl::Error(GL_INVALID_OPERATION);
if (mState.getDepthAttachment() && (mask & GL_DEPTH_BUFFER_BIT) != 0)
{
// TODO(jmadill): Depth clear
UNIMPLEMENTED();
}
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
......
...@@ -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;
}; };
......
...@@ -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,9 +144,22 @@ class Image final : public WrappedObject<VkImage> ...@@ -119,9 +144,22 @@ class Image final : public WrappedObject<VkImage>
~Image() override; ~Image() override;
void changeLayout(VkImageAspectFlags aspectMask, Error init(const VkImageCreateInfo &createInfo);
VkImageLayout newLayout,
CommandBuffer *commandBuffer); void changeLayoutTop(VkImageAspectFlags aspectMask,
VkImageLayout newLayout,
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