Commit 035fd6b3 by Jamie Madill Committed by Commit Bot

Vulkan: Implement very basic textures.

This is a quick implementation which supports only one backing Image and one type of ImageView at a time, for 2D texture only. It also implements a helper class for finding compatible memory pools. It's possible we can keep a cache of memory pool indexes given the guarantees the Vulkan spec has on compatible memory types (see the documentation for VkMemoryRequirements). BUG=angleproject:2167 Change-Id: I1d7a8eaec90f240273ad75194e23430d6d4c5dc1 Reviewed-on: https://chromium-review.googlesource.com/680000 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org>
parent 488130e0
...@@ -27,9 +27,10 @@ BufferVk::~BufferVk() ...@@ -27,9 +27,10 @@ BufferVk::~BufferVk()
void BufferVk::destroy(const gl::Context *context) void BufferVk::destroy(const gl::Context *context)
{ {
VkDevice device = GetImplAs<ContextVk>(context)->getDevice(); ContextVk *contextVk = GetImplAs<ContextVk>(context);
RendererVk *renderer = contextVk->getRenderer();
mBuffer.destroy(device); renderer->enqueueGarbageOrDeleteNow(*this, std::move(mBuffer));
} }
gl::Error BufferVk::setData(const gl::Context *context, gl::Error BufferVk::setData(const gl::Context *context,
......
...@@ -283,7 +283,8 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context, ...@@ -283,7 +283,8 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context,
vk::Image *readImage = renderTarget->image; vk::Image *readImage = renderTarget->image;
vk::StagingImage stagingImage; vk::StagingImage stagingImage;
ANGLE_TRY(renderer->createStagingImage(TextureDimension::TEX_2D, *renderTarget->format, ANGLE_TRY(renderer->createStagingImage(TextureDimension::TEX_2D, *renderTarget->format,
renderTarget->extents, &stagingImage)); renderTarget->extents, vk::StagingUsage::Read,
&stagingImage));
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(contextVk->getStartedCommandBuffer(&commandBuffer)); ANGLE_TRY(contextVk->getStartedCommandBuffer(&commandBuffer));
...@@ -332,10 +333,6 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context, ...@@ -332,10 +333,6 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context,
stagingImage.getDeviceMemory().unmap(device); stagingImage.getDeviceMemory().unmap(device);
renderer->enqueueGarbage(renderer->getCurrentQueueSerial(), std::move(stagingImage)); renderer->enqueueGarbage(renderer->getCurrentQueueSerial(), std::move(stagingImage));
stagingImage.getImage().destroy(renderer->getDevice());
stagingImage.destroy(device);
return vk::NoError(); return vk::NoError();
} }
......
...@@ -93,7 +93,6 @@ RendererVk::RendererVk() ...@@ -93,7 +93,6 @@ 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),
mHostVisibleMemoryIndex(std::numeric_limits<uint32_t>::max()),
mGlslangWrapper(nullptr), mGlslangWrapper(nullptr),
mLastCompletedQueueSerial(mQueueSerialFactory.generate()), mLastCompletedQueueSerial(mQueueSerialFactory.generate()),
mCurrentQueueSerial(mQueueSerialFactory.generate()), mCurrentQueueSerial(mQueueSerialFactory.generate()),
...@@ -338,21 +337,8 @@ vk::Error RendererVk::initialize(const egl::AttributeMap &attribs, const char *w ...@@ -338,21 +337,8 @@ vk::Error RendererVk::initialize(const egl::AttributeMap &attribs, const char *w
ANGLE_TRY(initializeDevice(firstGraphicsQueueFamily)); ANGLE_TRY(initializeDevice(firstGraphicsQueueFamily));
} }
VkPhysicalDeviceMemoryProperties memoryProperties; // Store the physical device memory properties so we can find the right memory pools.
vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memoryProperties); mMemoryProperties.init(mPhysicalDevice);
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);
mGlslangWrapper = GlslangWrapper::GetReference(); mGlslangWrapper = GlslangWrapper::GetReference();
...@@ -540,7 +526,10 @@ void RendererVk::generateCaps(gl::Caps *outCaps, ...@@ -540,7 +526,10 @@ void RendererVk::generateCaps(gl::Caps *outCaps,
outCaps->maxDrawBuffers = 1; outCaps->maxDrawBuffers = 1;
outCaps->maxVertexAttributes = gl::MAX_VERTEX_ATTRIBS; outCaps->maxVertexAttributes = gl::MAX_VERTEX_ATTRIBS;
outCaps->maxVertexAttribBindings = gl::MAX_VERTEX_ATTRIB_BINDINGS; outCaps->maxVertexAttribBindings = gl::MAX_VERTEX_ATTRIB_BINDINGS;
outCaps->maxVaryingVectors = 16; outCaps->maxVaryingVectors = 16;
outCaps->maxTextureImageUnits = 1;
outCaps->maxCombinedTextureImageUnits = 1;
outCaps->max2DTextureSize = 1024;
// Enable this for simple buffer readback testing, but some functionality is missing. // Enable this for simple buffer readback testing, but some functionality is missing.
// TODO(jmadill): Support full mapBufferRange extension. // TODO(jmadill): Support full mapBufferRange extension.
...@@ -774,13 +763,11 @@ vk::Error RendererVk::submitFrame(const VkSubmitInfo &submitInfo) ...@@ -774,13 +763,11 @@ vk::Error RendererVk::submitFrame(const VkSubmitInfo &submitInfo)
vk::Error RendererVk::createStagingImage(TextureDimension dimension, vk::Error RendererVk::createStagingImage(TextureDimension dimension,
const vk::Format &format, const vk::Format &format,
const gl::Extents &extent, const gl::Extents &extent,
vk::StagingUsage usage,
vk::StagingImage *imageOut) vk::StagingImage *imageOut)
{ {
ASSERT(mHostVisibleMemoryIndex != std::numeric_limits<uint32_t>::max()); ANGLE_TRY(imageOut->init(mDevice, mCurrentQueueFamilyIndex, mMemoryProperties, dimension,
format.native, extent, usage));
ANGLE_TRY(imageOut->init(mDevice, mCurrentQueueFamilyIndex, mHostVisibleMemoryIndex, dimension,
format.native, extent));
return vk::NoError(); return vk::NoError();
} }
......
...@@ -66,6 +66,7 @@ class RendererVk : angle::NonCopyable ...@@ -66,6 +66,7 @@ class RendererVk : angle::NonCopyable
vk::Error createStagingImage(TextureDimension dimension, vk::Error createStagingImage(TextureDimension dimension,
const vk::Format &format, const vk::Format &format,
const gl::Extents &extent, const gl::Extents &extent,
vk::StagingUsage usage,
vk::StagingImage *imageOut); vk::StagingImage *imageOut);
GlslangWrapper *getGlslangWrapper(); GlslangWrapper *getGlslangWrapper();
...@@ -80,18 +81,22 @@ class RendererVk : angle::NonCopyable ...@@ -80,18 +81,22 @@ class RendererVk : angle::NonCopyable
} }
template <typename T> template <typename T>
void enqueueGarbageOrDeleteNow(const ResourceVk &resouce, T &&object) void enqueueGarbageOrDeleteNow(const ResourceVk &resource, T &&object)
{ {
if (resouce.getDeleteSchedule(mLastCompletedQueueSerial) == DeleteSchedule::NOW) if (resource.getDeleteSchedule(mLastCompletedQueueSerial) == DeleteSchedule::NOW)
{ {
object.destroy(mDevice); object.destroy(mDevice);
} }
else else
{ {
enqueueGarbage(resouce.getStoredQueueSerial(), std::move(object)); enqueueGarbage(resource.getStoredQueueSerial(), std::move(object));
} }
} }
uint32_t getQueueFamilyIndex() const { return mCurrentQueueFamilyIndex; }
const vk::MemoryProperties &getMemoryProperties() const { return mMemoryProperties; }
private: private:
void ensureCapsInitialized() const; void ensureCapsInitialized() const;
void generateCaps(gl::Caps *outCaps, void generateCaps(gl::Caps *outCaps,
...@@ -122,7 +127,6 @@ class RendererVk : angle::NonCopyable ...@@ -122,7 +127,6 @@ class RendererVk : angle::NonCopyable
VkDevice mDevice; VkDevice mDevice;
vk::CommandPool mCommandPool; vk::CommandPool mCommandPool;
vk::CommandBuffer mCommandBuffer; vk::CommandBuffer mCommandBuffer;
uint32_t mHostVisibleMemoryIndex;
GlslangWrapper *mGlslangWrapper; GlslangWrapper *mGlslangWrapper;
SerialFactory mQueueSerialFactory; SerialFactory mQueueSerialFactory;
Serial mLastCompletedQueueSerial; Serial mLastCompletedQueueSerial;
...@@ -130,6 +134,7 @@ class RendererVk : angle::NonCopyable ...@@ -130,6 +134,7 @@ class RendererVk : angle::NonCopyable
std::vector<vk::CommandBufferAndSerial> mInFlightCommands; std::vector<vk::CommandBufferAndSerial> mInFlightCommands;
std::vector<vk::FenceAndSerial> mInFlightFences; std::vector<vk::FenceAndSerial> mInFlightFences;
std::vector<std::unique_ptr<vk::IGarbageObject>> mGarbage; std::vector<std::unique_ptr<vk::IGarbageObject>> mGarbage;
vk::MemoryProperties mMemoryProperties;
}; };
} // namespace rx } // namespace rx
......
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
#include "libANGLE/renderer/vulkan/TextureVk.h" #include "libANGLE/renderer/vulkan/TextureVk.h"
#include "common/debug.h" #include "common/debug.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
namespace rx namespace rx
{ {
...@@ -22,6 +26,18 @@ TextureVk::~TextureVk() ...@@ -22,6 +26,18 @@ TextureVk::~TextureVk()
{ {
} }
gl::Error TextureVk::onDestroy(const gl::Context *context)
{
ContextVk *contextVk = GetImplAs<ContextVk>(context);
RendererVk *renderer = contextVk->getRenderer();
renderer->enqueueGarbageOrDeleteNow(*this, std::move(mImage));
renderer->enqueueGarbageOrDeleteNow(*this, std::move(mDeviceMemory));
renderer->enqueueGarbageOrDeleteNow(*this, std::move(mImageView));
return gl::NoError();
}
gl::Error TextureVk::setImage(const gl::Context *context, gl::Error TextureVk::setImage(const gl::Context *context,
GLenum target, GLenum target,
size_t level, size_t level,
...@@ -32,8 +48,140 @@ gl::Error TextureVk::setImage(const gl::Context *context, ...@@ -32,8 +48,140 @@ gl::Error TextureVk::setImage(const gl::Context *context,
const gl::PixelUnpackState &unpack, const gl::PixelUnpackState &unpack,
const uint8_t *pixels) const uint8_t *pixels)
{ {
UNIMPLEMENTED(); // TODO(jmadill): support multi-level textures.
return gl::InternalError(); ASSERT(level == 0);
// TODO(jmadill): support texture re-definition.
ASSERT(!mImage.valid());
// TODO(jmadill): support other types of textures.
ASSERT(target == GL_TEXTURE_2D);
// Convert internalFormat to sized internal format.
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
const vk::Format &vkFormat = vk::Format::Get(formatInfo.sizedInternalFormat);
VkImageCreateInfo imageInfo;
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.pNext = nullptr;
imageInfo.flags = 0;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.format = vkFormat.native;
imageInfo.extent.width = size.width;
imageInfo.extent.height = size.height;
imageInfo.extent.depth = size.depth;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
// TODO(jmadill): Are all these image transfer bits necessary?
imageInfo.usage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.queueFamilyIndexCount = 0;
imageInfo.pQueueFamilyIndices = nullptr;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
ContextVk *contextVk = GetImplAs<ContextVk>(context);
VkDevice device = contextVk->getDevice();
ANGLE_TRY(mImage.init(device, imageInfo));
// Allocate the device memory for the image.
// TODO(jmadill): Use more intelligent device memory allocation.
VkMemoryRequirements memoryRequirements;
mImage.getMemoryRequirements(device, &memoryRequirements);
RendererVk *renderer = contextVk->getRenderer();
uint32_t memoryIndex = renderer->getMemoryProperties().findCompatibleMemoryIndex(
memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkMemoryAllocateInfo allocateInfo;
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocateInfo.pNext = nullptr;
allocateInfo.allocationSize = memoryRequirements.size;
allocateInfo.memoryTypeIndex = memoryIndex;
ANGLE_TRY(mDeviceMemory.allocate(device, allocateInfo));
ANGLE_TRY(mImage.bindMemory(device, mDeviceMemory));
VkImageViewCreateInfo viewInfo;
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.pNext = nullptr;
viewInfo.flags = 0;
viewInfo.image = mImage.getHandle();
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = vkFormat.native;
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
ANGLE_TRY(mImageView.init(device, viewInfo));
// Handle initial data.
// TODO(jmadill): Consider re-using staging texture.
if (pixels)
{
vk::StagingImage stagingImage;
ANGLE_TRY(renderer->createStagingImage(TextureDimension::TEX_2D, vkFormat, size,
vk::StagingUsage::Write, &stagingImage));
GLuint inputRowPitch = 0;
ANGLE_TRY_RESULT(
formatInfo.computeRowPitch(type, size.width, unpack.alignment, unpack.rowLength),
inputRowPitch);
GLuint inputDepthPitch = 0;
ANGLE_TRY_RESULT(
formatInfo.computeDepthPitch(size.height, unpack.imageHeight, inputRowPitch),
inputDepthPitch);
// TODO(jmadill): skip images for 3D Textures.
bool applySkipImages = false;
GLuint inputSkipBytes = 0;
ANGLE_TRY_RESULT(
formatInfo.computeSkipBytes(inputRowPitch, inputDepthPitch, unpack, applySkipImages),
inputSkipBytes);
auto loadFunction = vkFormat.getLoadFunctions()(type);
uint8_t *mapPointer = nullptr;
ANGLE_TRY(
stagingImage.getDeviceMemory().map(device, 0, stagingImage.getSize(), 0, &mapPointer));
const uint8_t *source = pixels + inputSkipBytes;
loadFunction.loadFunction(size.width, size.height, size.depth, source, inputRowPitch,
inputDepthPitch, mapPointer, inputRowPitch, inputDepthPitch);
stagingImage.getDeviceMemory().unmap(device);
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(contextVk->getStartedCommandBuffer(&commandBuffer));
setQueueSerial(renderer->getCurrentQueueSerial());
stagingImage.getImage().changeLayoutTop(
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, commandBuffer);
mImage.changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
commandBuffer);
gl::Box wholeRegion(0, 0, 0, size.width, size.height, size.depth);
commandBuffer->copySingleImage(stagingImage.getImage(), mImage, wholeRegion,
VK_IMAGE_ASPECT_COLOR_BIT);
// TODO(jmadill): Re-use staging images.
renderer->enqueueGarbage(renderer->getCurrentQueueSerial(), std::move(stagingImage));
}
return gl::NoError();
} }
gl::Error TextureVk::setSubImage(const gl::Context *context, gl::Error TextureVk::setSubImage(const gl::Context *context,
......
...@@ -11,15 +11,17 @@ ...@@ -11,15 +11,17 @@
#define LIBANGLE_RENDERER_VULKAN_TEXTUREVK_H_ #define LIBANGLE_RENDERER_VULKAN_TEXTUREVK_H_
#include "libANGLE/renderer/TextureImpl.h" #include "libANGLE/renderer/TextureImpl.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
namespace rx namespace rx
{ {
class TextureVk : public TextureImpl class TextureVk : public TextureImpl, public ResourceVk
{ {
public: public:
TextureVk(const gl::TextureState &state); TextureVk(const gl::TextureState &state);
~TextureVk() override; ~TextureVk() override;
gl::Error onDestroy(const gl::Context *context) override;
gl::Error setImage(const gl::Context *context, gl::Error setImage(const gl::Context *context,
GLenum target, GLenum target,
...@@ -107,6 +109,12 @@ class TextureVk : public TextureImpl ...@@ -107,6 +109,12 @@ class TextureVk : public TextureImpl
gl::Error initializeContents(const gl::Context *context, gl::Error initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override; const gl::ImageIndex &imageIndex) override;
private:
// TODO(jmadill): support a more flexible storage back-end.
vk::Image mImage;
vk::DeviceMemory mDeviceMemory;
vk::ImageView mImageView;
}; };
} // namespace rx } // namespace rx
......
...@@ -62,6 +62,7 @@ VkAccessFlags GetBasicLayoutAccessFlags(VkImageLayout layout) ...@@ -62,6 +62,7 @@ VkAccessFlags GetBasicLayoutAccessFlags(VkImageLayout layout)
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: case VK_IMAGE_LAYOUT_GENERAL:
case VK_IMAGE_LAYOUT_PREINITIALIZED:
return 0; return 0;
default: default:
// TODO(jmadill): Investigate other flags. // TODO(jmadill): Investigate other flags.
...@@ -69,6 +70,23 @@ VkAccessFlags GetBasicLayoutAccessFlags(VkImageLayout layout) ...@@ -69,6 +70,23 @@ VkAccessFlags GetBasicLayoutAccessFlags(VkImageLayout layout)
return 0; return 0;
} }
} }
VkImageUsageFlags GetImageUsageFlags(vk::StagingUsage usage)
{
switch (usage)
{
case vk::StagingUsage::Read:
return VK_IMAGE_USAGE_TRANSFER_DST_BIT;
case vk::StagingUsage::Write:
return VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
case vk::StagingUsage::Both:
return (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
default:
UNREACHABLE();
return 0;
}
}
} // anonymous namespace } // anonymous namespace
// Mirrors std_validation_str in loader.h // Mirrors std_validation_str in loader.h
...@@ -459,6 +477,7 @@ Error Image::init(VkDevice device, const VkImageCreateInfo &createInfo) ...@@ -459,6 +477,7 @@ Error Image::init(VkDevice device, const VkImageCreateInfo &createInfo)
{ {
ASSERT(!valid()); ASSERT(!valid());
ANGLE_VK_TRY(vkCreateImage(device, &createInfo, nullptr, &mHandle)); ANGLE_VK_TRY(vkCreateImage(device, &createInfo, nullptr, &mHandle));
mCurrentLayout = createInfo.initialLayout;
return NoError(); return NoError();
} }
...@@ -697,10 +716,11 @@ void StagingImage::retain(VkDevice device, StagingImage &&other) ...@@ -697,10 +716,11 @@ void StagingImage::retain(VkDevice device, StagingImage &&other)
Error StagingImage::init(VkDevice device, Error StagingImage::init(VkDevice device,
uint32_t queueFamilyIndex, uint32_t queueFamilyIndex,
uint32_t hostVisibleMemoryIndex, const vk::MemoryProperties &memoryProperties,
TextureDimension dimension, TextureDimension dimension,
VkFormat format, VkFormat format,
const gl::Extents &extent) const gl::Extents &extent,
StagingUsage usage)
{ {
VkImageCreateInfo createInfo; VkImageCreateInfo createInfo;
...@@ -716,26 +736,30 @@ Error StagingImage::init(VkDevice device, ...@@ -716,26 +736,30 @@ Error StagingImage::init(VkDevice device,
createInfo.arrayLayers = 1; createInfo.arrayLayers = 1;
createInfo.samples = VK_SAMPLE_COUNT_1_BIT; createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
createInfo.tiling = VK_IMAGE_TILING_LINEAR; createInfo.tiling = VK_IMAGE_TILING_LINEAR;
createInfo.usage = (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); createInfo.usage = GetImageUsageFlags(usage);
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 1; createInfo.queueFamilyIndexCount = 1;
createInfo.pQueueFamilyIndices = &queueFamilyIndex; createInfo.pQueueFamilyIndices = &queueFamilyIndex;
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
// Use Preinitialized for writable staging images - in these cases we want to map the memory
// before we do a copy. For readback images, use an undefined layout.
createInfo.initialLayout = usage == vk::StagingUsage::Read ? VK_IMAGE_LAYOUT_UNDEFINED
: VK_IMAGE_LAYOUT_PREINITIALIZED;
ANGLE_TRY(mImage.init(device, createInfo)); ANGLE_TRY(mImage.init(device, createInfo));
VkMemoryRequirements memoryRequirements; VkMemoryRequirements memoryRequirements;
mImage.getMemoryRequirements(device, &memoryRequirements); mImage.getMemoryRequirements(device, &memoryRequirements);
// Ensure we can read this memory. // Find the right kind of memory index.
ANGLE_VK_CHECK((memoryRequirements.memoryTypeBits & (1 << hostVisibleMemoryIndex)) != 0, uint32_t memoryIndex = memoryProperties.findCompatibleMemoryIndex(
VK_ERROR_VALIDATION_FAILED_EXT); memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
VkMemoryAllocateInfo allocateInfo; VkMemoryAllocateInfo allocateInfo;
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocateInfo.pNext = nullptr; allocateInfo.pNext = nullptr;
allocateInfo.allocationSize = memoryRequirements.size; allocateInfo.allocationSize = memoryRequirements.size;
allocateInfo.memoryTypeIndex = hostVisibleMemoryIndex; allocateInfo.memoryTypeIndex = memoryIndex;
ANGLE_TRY(mDeviceMemory.allocate(device, allocateInfo)); ANGLE_TRY(mDeviceMemory.allocate(device, allocateInfo));
ANGLE_TRY(mImage.bindMemory(device, mDeviceMemory)); ANGLE_TRY(mImage.bindMemory(device, mDeviceMemory));
...@@ -871,6 +895,38 @@ VkResult Fence::getStatus(VkDevice device) const ...@@ -871,6 +895,38 @@ VkResult Fence::getStatus(VkDevice device) const
return vkGetFenceStatus(device, mHandle); return vkGetFenceStatus(device, mHandle);
} }
// MemoryProperties implementation.
MemoryProperties::MemoryProperties() : mMemoryProperties{0}
{
}
void MemoryProperties::init(VkPhysicalDevice physicalDevice)
{
ASSERT(mMemoryProperties.memoryTypeCount == 0);
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &mMemoryProperties);
ASSERT(mMemoryProperties.memoryTypeCount > 0);
}
uint32_t MemoryProperties::findCompatibleMemoryIndex(uint32_t bitMask, uint32_t propertyFlags) const
{
ASSERT(mMemoryProperties.memoryTypeCount > 0);
// TODO(jmadill): Cache compatible memory indexes after finding them once.
for (size_t memoryIndex : angle::BitSet32<32>(bitMask))
{
ASSERT(memoryIndex < mMemoryProperties.memoryTypeCount);
if ((mMemoryProperties.memoryTypes[memoryIndex].propertyFlags & propertyFlags) ==
propertyFlags)
{
return static_cast<uint32_t>(memoryIndex);
}
}
UNREACHABLE();
return std::numeric_limits<uint32_t>::max();
}
} // namespace vk } // namespace vk
Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProps, Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProps,
......
...@@ -89,6 +89,18 @@ class Image; ...@@ -89,6 +89,18 @@ class Image;
class Pipeline; class Pipeline;
class RenderPass; class RenderPass;
class MemoryProperties final : angle::NonCopyable
{
public:
MemoryProperties();
void init(VkPhysicalDevice physicalDevice);
uint32_t findCompatibleMemoryIndex(uint32_t bitMask, uint32_t propertyFlags) const;
private:
VkPhysicalDeviceMemoryProperties mMemoryProperties;
};
class Error final class Error final
{ {
public: public:
...@@ -321,6 +333,13 @@ class RenderPass final : public WrappedObject<RenderPass, VkRenderPass> ...@@ -321,6 +333,13 @@ class RenderPass final : public WrappedObject<RenderPass, VkRenderPass>
Error init(VkDevice device, const VkRenderPassCreateInfo &createInfo); Error init(VkDevice device, const VkRenderPassCreateInfo &createInfo);
}; };
enum class StagingUsage
{
Read,
Write,
Both,
};
class StagingImage final : angle::NonCopyable class StagingImage final : angle::NonCopyable
{ {
public: public:
...@@ -331,10 +350,11 @@ class StagingImage final : angle::NonCopyable ...@@ -331,10 +350,11 @@ class StagingImage final : angle::NonCopyable
vk::Error init(VkDevice device, vk::Error init(VkDevice device,
uint32_t queueFamilyIndex, uint32_t queueFamilyIndex,
uint32_t hostVisibleMemoryIndex, const MemoryProperties &memoryProperties,
TextureDimension dimension, TextureDimension dimension,
VkFormat format, VkFormat format,
const gl::Extents &extent); const gl::Extents &extent,
StagingUsage usage);
Image &getImage() { return mImage; } Image &getImage() { return mImage; }
const Image &getImage() const { return mImage; } const Image &getImage() const { return mImage; }
......
...@@ -330,6 +330,26 @@ void main() ...@@ -330,6 +330,26 @@ void main()
EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow); EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow);
} }
// Creates a texture, no other operations.
TEST_P(SimpleOperationTest, CreateTexture2DNoData)
{
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
ASSERT_GL_NO_ERROR();
}
// Creates a texture, no other operations.
TEST_P(SimpleOperationTest, CreateTexture2DWithData)
{
std::vector<GLColor> colors(16 * 16, GLColor::red);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
ASSERT_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