# all needed deps and SPIRV-Tools package is needed
SET(DALI_LDFLAGS ${DALI_LDFLAGS} ${GLSLANG_LDFLAGS} -lSPIRV ${SPIRVTOOLS_LDFLAGS} -lglslang-default-resource-limits)
ENDIF()
-
+ LIST(APPEND DALI_CFLAGS ${GLSLANG_CFLAGS})
ENDIF()
IF(LIBUV_X11_PROFILE)
/*
-* Copyright (c) 2024 Samsung Electronics Co., Ltd.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*
-*/
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
#include <dali/integration-api/debug.h>
#include <dali/internal/graphics/common/shader-parser.h>
}
}
-} // namespace Dali::Internal::ShaderParser
\ No newline at end of file
+} // namespace Dali::Internal::ShaderParser
{
BufferImpl* BufferImpl::New(Device& device, size_t size, vk::BufferUsageFlags usageFlags)
{
- return New(device, size, vk::SharingMode(vk::SharingMode::eExclusive), usageFlags, vk::MemoryPropertyFlags(vk::MemoryPropertyFlagBits::eHostVisible));
+ return New(device, size, vk::SharingMode(vk::SharingMode::eExclusive), usageFlags, vk::MemoryPropertyFlags(vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent));
}
BufferImpl* BufferImpl::New(Device& device, size_t size, vk::SharingMode sharingMode, vk::BufferUsageFlags usageFlags, vk::MemoryPropertyFlags memoryProperties)
requirements.memoryTypeBits,
memoryProperties);
- mMemory = std::make_unique<MemoryImpl>(mDevice, size_t(requirements.size), size_t(requirements.alignment), ((memoryProperties & vk::MemoryPropertyFlagBits::eHostVisible) == vk::MemoryPropertyFlagBits::eHostVisible));
+ mMemory = std::make_unique<MemoryImpl>(mDevice, size_t(requirements.size), size_t(requirements.alignment), memoryProperties);
auto allocateInfo = vk::MemoryAllocateInfo{}
.setMemoryTypeIndex(memoryTypeIndex)
#include <dali/internal/graphics/vulkan-impl/vulkan-command-pool-impl.h>
#include <dali/internal/graphics/vulkan-impl/vulkan-framebuffer-impl.h>
#include <dali/internal/graphics/vulkan-impl/vulkan-image-impl.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-image-view-impl.h>
#include <dali/internal/graphics/vulkan-impl/vulkan-pipeline-impl.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-sampler-impl.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-sampler.h>
#include <dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-texture.h>
#include <dali/internal/graphics/vulkan-impl/vulkan-types.h>
#include <dali/internal/graphics/vulkan/vulkan-device.h>
}
}
+void CommandBufferImpl::BindVertexBuffers(
+ uint32_t firstBinding,
+ const std::vector<BufferImpl*>& buffers,
+ const std::vector<uint32_t>& offsets)
+{
+ // update list of used resources and create an array of VkBuffers
+ std::vector<vk::Buffer> vkBuffers;
+ vkBuffers.reserve(buffers.size());
+ for(auto&& buffer : buffers)
+ {
+ vkBuffers.emplace_back(buffer->GetVkHandle());
+ }
+ std::vector<vk::DeviceSize> vkOffsets;
+ vkOffsets.reserve(offsets.size());
+ for(auto&& offset : offsets)
+ {
+ vkOffsets.emplace_back(static_cast<vk::DeviceSize>(offset));
+ }
+ mCommandBuffer.bindVertexBuffers(firstBinding, vkBuffers.size(), vkBuffers.data(), vkOffsets.data());
+}
+
+void CommandBufferImpl::BindIndexBuffer(
+ BufferImpl& buffer,
+ uint32_t offset,
+ Format format)
+{
+ if(format == Graphics::Format::R16_UINT)
+ {
+ mCommandBuffer.bindIndexBuffer(buffer.GetVkHandle(), offset, vk::IndexType::eUint16);
+ }
+ else if(format == Graphics::Format::R32_UINT)
+ {
+ mCommandBuffer.bindIndexBuffer(buffer.GetVkHandle(), offset, vk::IndexType::eUint32);
+ }
+}
+
+void CommandBufferImpl::BindUniformBuffers(const std::vector<UniformBufferBinding>& bindings)
+{
+ // Needs descriptor set pools.
+}
+
+void CommandBufferImpl::BindTextures(const std::vector<TextureBinding>& textureBindings)
+{
+ for(const auto& textureBinding : textureBindings)
+ {
+ auto texture = static_cast<const Vulkan::Texture*>(textureBinding.texture);
+ auto sampler = const_cast<Vulkan::Sampler*>(static_cast<const Vulkan::Sampler*>(textureBinding.sampler));
+ auto vkSampler = sampler ? sampler->GetImpl()->GetVkHandle() : nullptr;
+
+ auto image = texture->GetImage();
+ auto imageView = texture->GetImageView();
+
+ // test if image is valid, skip invalid image
+ if(!image || !image->GetVkHandle())
+ {
+ continue;
+ }
+
+ // Store: imageView, sampler & texture.binding for later use
+ // We don't know at this point what pipeline is bound (As dali-core
+ // binds the pipeline after calling this API)
+ mDeferredTextureBindings.emplace_back();
+ mDeferredTextureBindings.back().imageView = imageView->GetVkHandle();
+ mDeferredTextureBindings.back().sampler = vkSampler;
+ mDeferredTextureBindings.back().binding = textureBinding.binding;
+ }
+}
+
+void CommandBufferImpl::BindSamplers(const std::vector<SamplerBinding>& samplerBindings)
+{
+ // Unused in core
+}
+
vk::CommandBuffer CommandBufferImpl::GetVkHandle() const
{
return mCommandBuffer;
uint32_t firstVertex,
uint32_t firstInstance)
{
+ mCommandBuffer.draw(vertexCount, instanceCount, firstVertex, firstInstance);
}
void CommandBufferImpl::DrawIndexed(uint32_t indexCount,
int32_t vertexOffset,
uint32_t firstInstance)
{
+ mCommandBuffer.drawIndexed(indexCount,
+ instanceCount,
+ firstIndex,
+ static_cast<int32_t>(vertexOffset),
+ firstInstance);
+}
+
+void CommandBufferImpl::DrawIndexedIndirect(BufferImpl& buffer,
+ uint32_t offset,
+ uint32_t drawCount,
+ uint32_t stride)
+{
+ mCommandBuffer.drawIndexedIndirect(buffer.GetVkHandle(), static_cast<vk::DeviceSize>(offset), drawCount, stride);
+}
+
+void CommandBufferImpl::ExecuteCommandBuffers(std::vector<vk::CommandBuffer>& commandBuffers)
+{
+ mCommandBuffer.executeCommands(commandBuffers);
}
-void CommandBufferImpl::DrawIndexedIndirect(Graphics::Buffer& buffer,
- uint32_t offset,
- uint32_t drawCount,
- uint32_t stride)
+void CommandBufferImpl::SetScissor(Rect2D value)
{
+ mCommandBuffer.setScissor(0, 1, reinterpret_cast<vk::Rect2D*>(&value));
}
-void CommandBufferImpl::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& commandBuffers)
+void CommandBufferImpl::SetViewport(Viewport value)
{
+ mCommandBuffer.setViewport(0, 1, reinterpret_cast<vk::Viewport*>(&value));
}
} // namespace Vulkan
/** Final validation of the pipeline */
void ValidatePipeline();
+ void BindVertexBuffers(
+ uint32_t firstBinding,
+ const std::vector<Vulkan::BufferImpl*>& buffers,
+ const std::vector<uint32_t>& offsets);
+ void BindIndexBuffer(Vulkan::BufferImpl& buffer, uint32_t offset, Format format);
+ void BindUniformBuffers(const std::vector<UniformBufferBinding>& bindings);
+ void BindTextures(const std::vector<TextureBinding>& textureBindings);
+ void BindSamplers(const std::vector<SamplerBinding>& samplerBindings);
+
/** Returns Vulkan object associated with the buffer */
[[nodiscard]] vk::CommandBuffer GetVkHandle() const;
* @return Returns true if the command buffer is primary
*/
[[nodiscard]] bool IsPrimary() const;
-
/**
* Allows to issue custom VkRenderPassBeginInfo structure
* @param renderPassBeginInfo
*/
bool OnDestroy() override;
+ void SetScissor(Rect2D value);
+ void SetViewport(Viewport value);
+
void Draw(
uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstInstance);
void DrawIndexedIndirect(
- Graphics::Buffer& buffer,
- uint32_t offset,
- uint32_t drawCount,
- uint32_t stride);
+ BufferImpl& buffer,
+ uint32_t offset,
+ uint32_t drawCount,
+ uint32_t stride);
- void ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& commandBuffers);
+ void ExecuteCommandBuffers(std::vector<vk::CommandBuffer>& commandBuffers);
private:
/**
const vk::CommandBufferAllocateInfo& allocateInfo,
vk::CommandBuffer vulkanHandle);
+private: // Struct for deferring texture binding
+ struct DeferredTextureBinding
+ {
+ vk::ImageView imageView;
+ vk::Sampler sampler;
+ uint32_t binding;
+ };
+
private:
- CommandPool* mOwnerCommandPool;
- Device* mGraphicsDevice;
- uint32_t mPoolAllocationIndex;
- vk::CommandBufferAllocateInfo mAllocateInfo{};
+ CommandPool* mOwnerCommandPool;
+ Device* mGraphicsDevice;
+ uint32_t mPoolAllocationIndex;
+ vk::CommandBufferAllocateInfo mAllocateInfo{};
+ std::vector<DeferredTextureBinding> mDeferredTextureBindings;
vk::CommandBuffer mCommandBuffer{};
* limitations under the License.
*/
+#include <dali/internal/graphics/vulkan-impl/vulkan-buffer-impl.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-buffer.h>
#include <dali/internal/graphics/vulkan-impl/vulkan-command-buffer.h>
#include <dali/internal/graphics/vulkan-impl/vulkan-command-pool-impl.h>
#include <dali/internal/graphics/vulkan-impl/vulkan-framebuffer-impl.h>
namespace Dali::Graphics::Vulkan
{
+template<typename VT, typename GT>
+VT* ConstGraphicsCast(const GT* object)
+{
+ return const_cast<VT*>(static_cast<const VT*>(object));
+}
+
CommandBuffer::CommandBuffer(const Graphics::CommandBufferCreateInfo& createInfo, VulkanGraphicsController& controller)
: CommandBufferResource(createInfo, controller),
mCommandBufferImpl(nullptr)
}
void CommandBuffer::BindVertexBuffers(uint32_t firstBinding,
- const std::vector<const Graphics::Buffer*>& buffers,
+ const std::vector<const Graphics::Buffer*>& gfxBuffers,
const std::vector<uint32_t>& offsets)
{
+ std::vector<BufferImpl*> buffers;
+ buffers.reserve(gfxBuffers.size());
+ for(auto& gfxBuffer : gfxBuffers)
+ {
+ buffers.push_back(ConstGraphicsCast<Buffer, Graphics::Buffer>(gfxBuffer)->GetImpl());
+ }
+ mCommandBufferImpl->BindVertexBuffers(firstBinding, buffers, offsets);
+}
+
+void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& gfxBuffer,
+ uint32_t offset,
+ Format format)
+{
+ auto indexBuffer = ConstGraphicsCast<Buffer, Graphics::Buffer>(&gfxBuffer);
+ DALI_ASSERT_DEBUG(indexBuffer && indexBuffer->GetImpl());
+ mCommandBufferImpl->BindIndexBuffer(*indexBuffer->GetImpl(), offset, format);
}
void CommandBuffer::BindUniformBuffers(const std::vector<UniformBufferBinding>& bindings)
{
+ mCommandBufferImpl->BindUniformBuffers(bindings);
}
void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline)
void CommandBuffer::BindTextures(const std::vector<TextureBinding>& textureBindings)
{
+ mCommandBufferImpl->BindTextures(textureBindings);
}
void CommandBuffer::BindSamplers(const std::vector<SamplerBinding>& samplerBindings)
{
+ mCommandBufferImpl->BindSamplers(samplerBindings);
}
void CommandBuffer::BindPushConstants(void* data,
{
}
-void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& buffer,
- uint32_t offset,
- Format format)
-{
-}
-
void CommandBuffer::BeginRenderPass(Graphics::RenderPass* gfxRenderPass,
Graphics::RenderTarget* gfxRenderTarget,
Rect2D renderArea,
mCommandBufferImpl->EndRenderPass();
}
-void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& commandBuffers)
+void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& gfxCommandBuffers)
{
+ std::vector<vk::CommandBuffer> vkCommandBuffers;
+ vkCommandBuffers.reserve(gfxCommandBuffers.size());
+ for(auto& gfxCmdBuf : gfxCommandBuffers)
+ {
+ vkCommandBuffers.push_back(ConstGraphicsCast<CommandBuffer, Graphics::CommandBuffer>(gfxCmdBuf)->GetImpl()->GetVkHandle());
+ }
+ mCommandBufferImpl->ExecuteCommandBuffers(vkCommandBuffers);
}
void CommandBuffer::Draw(uint32_t vertexCount,
mCommandBufferImpl->DrawIndexed(indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
}
-void CommandBuffer::DrawIndexedIndirect(Graphics::Buffer& buffer,
+void CommandBuffer::DrawIndexedIndirect(Graphics::Buffer& gfxBuffer,
uint32_t offset,
uint32_t drawCount,
uint32_t stride)
{
- mCommandBufferImpl->DrawIndexedIndirect(buffer, offset, drawCount, stride);
+ auto buffer = ConstGraphicsCast<Buffer, Graphics::Buffer>(&gfxBuffer)->GetImpl();
+
+ mCommandBufferImpl->DrawIndexedIndirect(*buffer, offset, drawCount, stride);
}
void CommandBuffer::DrawNative(const DrawNativeInfo* drawInfo)
void CommandBuffer::SetScissor(Rect2D value)
{
+ // @todo Vulkan accepts array of scissors... add to API
+ mCommandBufferImpl->SetScissor(value);
}
void CommandBuffer::SetScissorTestEnable(bool value)
{
+ // Enabled by default. What does disabling test do?!
+ // Probably should force pipeline to not use dynamic scissor state
}
void CommandBuffer::SetViewport(Viewport value)
{
+ mCommandBufferImpl->SetViewport(value);
}
void CommandBuffer::SetViewportEnable(bool value)
{
+ // Enabled by default. What does disabling test do?!
+ // Probably should force pipeline to not use dynamic viewport state
}
void CommandBuffer::SetColorMask(bool enabled)
{
namespace Vulkan
{
-
Image* Image::New(Device& graphicsDevice, const vk::ImageCreateInfo& createInfo)
{
auto image = new Image(graphicsDevice, createInfo, nullptr);
mMemory = std::make_unique<MemoryImpl>(mDevice,
size_t(requirements.size),
size_t(requirements.alignment),
- (memoryProperties & vk::MemoryPropertyFlagBits::eHostVisible) == vk::MemoryPropertyFlagBits::eHostVisible);
+ memoryProperties);
auto allocateInfo = vk::MemoryAllocateInfo{}
.setMemoryTypeIndex(memoryTypeIndex)
auto allocator = &mDevice.GetAllocator();
auto memory = mMemory->ReleaseVkObject();
- mDevice.DiscardResource([device, image, memory, allocator]()
- { DestroyVulkanResources(device, image, memory, allocator); });
+ mDevice.DiscardResource([device, image, memory, allocator]() { DestroyVulkanResources(device, image, memory, allocator); });
}
}
namespace Dali::Graphics::Vulkan
{
-
-MemoryImpl::MemoryImpl(Device& device, size_t memSize, size_t memAlign, bool isHostVisible)
+MemoryImpl::MemoryImpl(Device& device, size_t memSize, size_t memAlign, vk::MemoryPropertyFlags memoryProperties)
: mDevice(device),
deviceMemory(nullptr),
size(memSize),
alignment(memAlign),
mappedPtr(nullptr),
mappedSize(0u),
- hostVisible(isHostVisible)
+ mMemoryProperties(memoryProperties)
{
}
void MemoryImpl::Flush()
{
- vk::Result result = mDevice.GetLogicalDevice().flushMappedMemoryRanges({vk::MappedMemoryRange{}
- .setSize(mappedSize)
- .setMemory(deviceMemory)
- .setOffset(0u)});
- DALI_ASSERT_ALWAYS(result == vk::Result::eSuccess); // If it's out of memory, may as well crash.
+ // Don't flush if we are using host coherent memory - it's un-necessary
+ if((mMemoryProperties & vk::MemoryPropertyFlagBits::eHostCoherent) != vk::MemoryPropertyFlagBits::eHostCoherent)
+ {
+ vk::Result result = mDevice.GetLogicalDevice().flushMappedMemoryRanges({vk::MappedMemoryRange{}
+ .setSize(mappedSize ? mappedSize : VK_WHOLE_SIZE)
+ .setMemory(deviceMemory)
+ .setOffset(0u)});
+
+ DALI_ASSERT_ALWAYS(result == vk::Result::eSuccess); // If it's out of memory, may as well crash.
+ }
}
vk::DeviceMemory MemoryImpl::GetVkHandle() const
namespace Dali::Graphics::Vulkan
{
-
class MemoryImpl
{
public:
- MemoryImpl(Device& device, size_t memSize, size_t memAlign, bool hostVisible);
+ MemoryImpl(Device& device, size_t memSize, size_t memAlign, vk::MemoryPropertyFlags memoryProperties);
~MemoryImpl();
}
// No copy constructor or assignment operator
- MemoryImpl(MemoryImpl&) = delete;
+ MemoryImpl(MemoryImpl&) = delete;
MemoryImpl& operator=(MemoryImpl&) = delete;
void* Map();
[[nodiscard]] vk::DeviceMemory GetVkHandle() const;
private:
- Device& mDevice;
- vk::DeviceMemory deviceMemory;
- size_t size;
- size_t alignment;
- void* mappedPtr;
- size_t mappedSize;
- bool hostVisible;
+ Device& mDevice;
+ vk::DeviceMemory deviceMemory;
+ size_t size;
+ size_t alignment;
+ void* mappedPtr;
+ size_t mappedSize;
+ vk::MemoryPropertyFlags mMemoryProperties;
};
} // namespace Dali::Graphics::Vulkan
// INTERNAL INCLUDES
#include <dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-sampler-impl.h>
namespace Dali::Graphics::Vulkan
{
+
+namespace
+{
+constexpr vk::Filter ConvertFilter(Dali::Graphics::SamplerFilter filter)
+{
+ switch(filter)
+ {
+ case Dali::Graphics::SamplerFilter::LINEAR:
+ return vk::Filter::eLinear;
+ case Dali::Graphics::SamplerFilter::NEAREST:
+ return vk::Filter::eNearest;
+ }
+ return vk::Filter{};
+}
+
+constexpr vk::SamplerAddressMode ConvertAddressMode(Dali::Graphics::SamplerAddressMode mode)
+{
+ switch(mode)
+ {
+ case Dali::Graphics::SamplerAddressMode::CLAMP_TO_EDGE:
+ return vk::SamplerAddressMode::eClampToEdge;
+ case Dali::Graphics::SamplerAddressMode::CLAMP_TO_BORDER:
+ return vk::SamplerAddressMode::eClampToBorder;
+ case Dali::Graphics::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE:
+ return vk::SamplerAddressMode::eMirrorClampToEdge;
+ case Dali::Graphics::SamplerAddressMode::MIRRORED_REPEAT:
+ return vk::SamplerAddressMode::eMirroredRepeat;
+ case Dali::Graphics::SamplerAddressMode::REPEAT:
+ return vk::SamplerAddressMode::eRepeat;
+ }
+ return vk::SamplerAddressMode{};
+}
+
+constexpr vk::SamplerMipmapMode ConvertMipmapMode(Dali::Graphics::SamplerMipmapMode mode)
+{
+ switch(mode)
+ {
+ case Dali::Graphics::SamplerMipmapMode::NONE:
+ return vk::SamplerMipmapMode::eNearest;
+ case Dali::Graphics::SamplerMipmapMode::LINEAR:
+ return vk::SamplerMipmapMode::eLinear;
+ case Dali::Graphics::SamplerMipmapMode::NEAREST:
+ return vk::SamplerMipmapMode::eNearest;
+ }
+ return vk::SamplerMipmapMode{};
+}
+
+} // namespace
+
Sampler::Sampler(const Graphics::SamplerCreateInfo& createInfo, VulkanGraphicsController& controller)
: SamplerResource(createInfo, controller)
{
bool Sampler::InitializeResource()
{
+ vk::SamplerCreateInfo createInfo{};
+ createInfo.setMinFilter(ConvertFilter(mCreateInfo.minFilter))
+ .setMagFilter(ConvertFilter(mCreateInfo.magFilter))
+ .setAddressModeU(ConvertAddressMode(mCreateInfo.addressModeU))
+ .setAddressModeV(ConvertAddressMode(mCreateInfo.addressModeV))
+ .setAddressModeW(ConvertAddressMode(mCreateInfo.addressModeW))
+ .setMipmapMode(ConvertMipmapMode(mCreateInfo.mipMapMode))
+ .setCompareEnable(vk::Bool32(mCreateInfo.compareEnable))
+ .setUnnormalizedCoordinates(vk::Bool32(mCreateInfo.unnormalizeCoordinates))
+ .setBorderColor(vk::BorderColor::eFloatOpaqueBlack)
+ .setAnisotropyEnable(vk::Bool32(mCreateInfo.anisotropyEnable))
+ .setMaxAnisotropy(mCreateInfo.maxAnisotropy)
+ .setMinLod(mCreateInfo.minLod)
+ .setMaxLod(mCreateInfo.maxLod);
+
+ mSamplerImpl = SamplerImpl::New(mController.GetGraphicsDevice(), createInfo);
+
return true;
}
namespace Dali::Graphics::Vulkan
{
using SamplerResource = Resource<Graphics::Sampler, Graphics::SamplerCreateInfo>;
+class SamplerImpl;
class Sampler : public SamplerResource
{
* @brief Called when UniquePtr<> on client-side dies
*/
void DiscardResource() override;
+
+ SamplerImpl* GetImpl()
+ {
+ return mSamplerImpl;
+ }
+
+private:
+ SamplerImpl* mSamplerImpl;
};
} // namespace Dali::Graphics::Vulkan