Compare commits
1 Commits
ebridgewat
...
gitIgnoreU
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a74936103 |
15
.gitignore
vendored
15
.gitignore
vendored
@@ -18,3 +18,18 @@ test*.json
|
|||||||
results
|
results
|
||||||
/compile_commands.json
|
/compile_commands.json
|
||||||
/.cache
|
/.cache
|
||||||
|
build/.cmake/
|
||||||
|
build/CMakeCache.txt
|
||||||
|
build/CMakeFiles/
|
||||||
|
build/Makefile
|
||||||
|
build/SPIRV-Tools*
|
||||||
|
build/cmake_install.cmake
|
||||||
|
build/compile_commands.json
|
||||||
|
build/filament/
|
||||||
|
build/include/
|
||||||
|
build/libs/
|
||||||
|
build/mac/ninja
|
||||||
|
build/samples/
|
||||||
|
build/shaders/
|
||||||
|
build/third_party/
|
||||||
|
build/tools/
|
||||||
|
|||||||
@@ -56,16 +56,10 @@ popd >/dev/null
|
|||||||
rm -rf out/check-headers
|
rm -rf out/check-headers
|
||||||
mkdir -p out/check-headers
|
mkdir -p out/check-headers
|
||||||
|
|
||||||
TMP_FILE=out/check-headers/temp.cpp
|
|
||||||
echo "Checking that public headers compile independently..."
|
echo "Checking that public headers compile independently..."
|
||||||
for include in "${includes[@]}"; do
|
for include in "${includes[@]}"; do
|
||||||
rm -f ${TMP_FILE}
|
|
||||||
echo "Checking ${include}"
|
echo "Checking ${include}"
|
||||||
if [[ "${include}" == "utils/Systrace.h" ]]; then
|
echo "#include <${include}>" >> out/check-headers/temp.cpp
|
||||||
# A necessary define before we can include utils/Systrace.h
|
clang -std=c++17 -I "${FILAMENT_HEADERS}" out/check-headers/temp.cpp -c -o /dev/null
|
||||||
echo "#define SYSTRACE_TAG SYSTRACE_TAG_DISABLED" >> ${TMP_FILE}
|
|
||||||
fi
|
|
||||||
echo "#include <${include}>" >> ${TMP_FILE}
|
|
||||||
clang -std=c++17 -I "${FILAMENT_HEADERS}" ${TMP_FILE} -c -o /dev/null
|
|
||||||
done
|
done
|
||||||
echo "Done!"
|
echo "Done!"
|
||||||
|
|||||||
@@ -194,8 +194,6 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
|||||||
src/vulkan/VulkanDriver.cpp
|
src/vulkan/VulkanDriver.cpp
|
||||||
src/vulkan/VulkanDriver.h
|
src/vulkan/VulkanDriver.h
|
||||||
src/vulkan/VulkanDriverFactory.h
|
src/vulkan/VulkanDriverFactory.h
|
||||||
src/vulkan/VulkanExternalImageManager.cpp
|
|
||||||
src/vulkan/VulkanExternalImageManager.h
|
|
||||||
src/vulkan/VulkanFboCache.cpp
|
src/vulkan/VulkanFboCache.cpp
|
||||||
src/vulkan/VulkanFboCache.h
|
src/vulkan/VulkanFboCache.h
|
||||||
src/vulkan/VulkanHandles.cpp
|
src/vulkan/VulkanHandles.cpp
|
||||||
|
|||||||
@@ -294,16 +294,6 @@ public:
|
|||||||
VkQueue getProtectedGraphicsQueue() const noexcept;
|
VkQueue getProtectedGraphicsQueue() const noexcept;
|
||||||
|
|
||||||
struct ExternalImageMetadata {
|
struct ExternalImageMetadata {
|
||||||
/**
|
|
||||||
* The Filament texture format.
|
|
||||||
*/
|
|
||||||
TextureFormat filamentFormat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Filament texture usage.
|
|
||||||
*/
|
|
||||||
TextureUsage filamentUsage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The width of the external image
|
* The width of the external image
|
||||||
*/
|
*/
|
||||||
@@ -314,6 +304,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The layerCount of the external image
|
||||||
|
*/
|
||||||
|
uint32_t layerCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The layer count of the external image
|
* The layer count of the external image
|
||||||
*/
|
*/
|
||||||
@@ -329,6 +324,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
VkFormat format;
|
VkFormat format;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An external buffer can be protected. This tells you if it is.
|
||||||
|
*/
|
||||||
|
bool isProtected;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of external format (opaque int) if used.
|
* The type of external format (opaque int) if used.
|
||||||
*/
|
*/
|
||||||
@@ -348,61 +348,20 @@ public:
|
|||||||
* Heap information
|
* Heap information
|
||||||
*/
|
*/
|
||||||
uint32_t memoryTypeBits;
|
uint32_t memoryTypeBits;
|
||||||
|
|
||||||
/**
|
|
||||||
* Ycbcr conversion components
|
|
||||||
*/
|
|
||||||
VkComponentMapping ycbcrConversionComponents;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ycbcr model
|
|
||||||
*/
|
|
||||||
VkSamplerYcbcrModelConversion ycbcrModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ycbcr range
|
|
||||||
*/
|
|
||||||
VkSamplerYcbcrRange ycbcrRange;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ycbcr x chroma offset
|
|
||||||
*/
|
|
||||||
VkChromaLocation xChromaOffset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ycbcr y chroma offset
|
|
||||||
*/
|
|
||||||
VkChromaLocation yChromaOffset;
|
|
||||||
};
|
};
|
||||||
|
virtual ExternalImageMetadata getExternalImageMetadata(ExternalImageHandleRef externalImage);
|
||||||
|
|
||||||
|
using ImageData = std::pair<VkImage, VkDeviceMemory>;
|
||||||
|
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
|
||||||
|
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
|
||||||
|
VkImageUsageFlags usage);
|
||||||
|
|
||||||
// Note that the image metadata might change per-frame, hence we need a method for extracting
|
virtual VkSampler createExternalSampler(SamplerYcbcrConversion chroma,
|
||||||
// it.
|
SamplerParams sampler, uint32_t internalFormat);
|
||||||
virtual ExternalImageMetadata extractExternalImageMetadata(ExternalImageHandleRef image) const {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ImageData {
|
virtual VkImageView createExternalImageView(SamplerYcbcrConversion chroma,
|
||||||
struct Bundle {
|
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
|
||||||
VkImage image = VK_NULL_HANDLE;
|
VkImageViewType viewType, VkComponentMapping swizzle);
|
||||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
inline bool valid() const noexcept {
|
|
||||||
return image != VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// It's possible for the external image to also have a known VK format. We need to create an
|
|
||||||
// image for that in case we are not looking to use an external "sampler" with this image.
|
|
||||||
Bundle internal;
|
|
||||||
|
|
||||||
// If we get a externalFormat in the metadata, then we should create an image with
|
|
||||||
// VK_FORMAT_UNDEFINED
|
|
||||||
Bundle external;
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ImageData createVkImageFromExternal(ExternalImageHandleRef image) const {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ExtensionSet getSwapchainInstanceExtensions() const;
|
virtual ExtensionSet getSwapchainInstanceExtensions() const;
|
||||||
@@ -415,6 +374,20 @@ private:
|
|||||||
// Platform dependent helper methods
|
// Platform dependent helper methods
|
||||||
static ExtensionSet getSwapchainInstanceExtensionsImpl();
|
static ExtensionSet getSwapchainInstanceExtensionsImpl();
|
||||||
|
|
||||||
|
static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage,
|
||||||
|
VkDevice device);
|
||||||
|
|
||||||
|
static ImageData createExternalImageDataImpl(ExternalImageHandleRef externalImage,
|
||||||
|
VkDevice device, const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
|
||||||
|
VkImageUsageFlags usage);
|
||||||
|
static VkSampler createExternalSamplerImpl(VkDevice device,
|
||||||
|
SamplerYcbcrConversion chroma, SamplerParams sampler,
|
||||||
|
uint32_t internalFormat);
|
||||||
|
static VkImageView createExternalImageViewImpl(VkDevice device,
|
||||||
|
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
||||||
|
VkImageSubresourceRange range, VkImageViewType viewType,
|
||||||
|
VkComponentMapping swizzle);
|
||||||
|
|
||||||
// Platform dependent helper methods
|
// Platform dependent helper methods
|
||||||
static SurfaceBundle createVkSurfaceKHRImpl(void* nativeWindow, VkInstance instance,
|
static SurfaceBundle createVkSurfaceKHRImpl(void* nativeWindow, VkInstance instance,
|
||||||
uint64_t flags) noexcept;
|
uint64_t flags) noexcept;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace filament::backend {
|
|||||||
|
|
||||||
class VulkanPlatformAndroid : public VulkanPlatform {
|
class VulkanPlatformAndroid : public VulkanPlatform {
|
||||||
public:
|
public:
|
||||||
ExternalImageHandle UTILS_PUBLIC createExternalImage(AHardwareBuffer const* buffer,
|
Platform::ExternalImageHandle UTILS_PUBLIC createExternalImage(AHardwareBuffer const* buffer,
|
||||||
bool sRGB) noexcept;
|
bool sRGB) noexcept;
|
||||||
|
|
||||||
struct UTILS_PUBLIC ExternalImageDescAndroid {
|
struct UTILS_PUBLIC ExternalImageDescAndroid {
|
||||||
@@ -39,26 +39,31 @@ public:
|
|||||||
ExternalImageDescAndroid UTILS_PUBLIC getExternalImageDesc(
|
ExternalImageDescAndroid UTILS_PUBLIC getExternalImageDesc(
|
||||||
ExternalImageHandleRef externalImage) const noexcept;
|
ExternalImageHandleRef externalImage) const noexcept;
|
||||||
|
|
||||||
virtual ExternalImageMetadata extractExternalImageMetadata(
|
|
||||||
ExternalImageHandleRef image) const override;
|
|
||||||
|
|
||||||
virtual ImageData createVkImageFromExternal(ExternalImageHandleRef image) const override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ExtensionSet getSwapchainInstanceExtensions() const override;
|
|
||||||
|
|
||||||
using SurfaceBundle = VulkanPlatform::SurfaceBundle;
|
|
||||||
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
|
|
||||||
uint64_t flags) const noexcept override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
|
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
|
||||||
AHardwareBuffer* aHardwareBuffer = nullptr;
|
AHardwareBuffer* aHardwareBuffer = nullptr;
|
||||||
bool sRGB = false;
|
bool sRGB = false;
|
||||||
|
unsigned int width; // Texture width
|
||||||
|
unsigned int height; // Texture height
|
||||||
|
TextureFormat format;// Texture format
|
||||||
|
TextureUsage usage; // Texture usage flags
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~ExternalImageVulkanAndroid() override;
|
~ExternalImageVulkanAndroid() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual ExternalImageMetadata getExternalImageMetadata(ExternalImageHandleRef externalImage);
|
||||||
|
|
||||||
|
using ImageData = VulkanPlatform::ImageData;
|
||||||
|
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
|
||||||
|
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
|
||||||
|
VkImageUsageFlags usage);
|
||||||
|
|
||||||
|
virtual ExtensionSet getSwapchainInstanceExtensions() const;
|
||||||
|
|
||||||
|
using SurfaceBundle = VulkanPlatform::SurfaceBundle;
|
||||||
|
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
|
||||||
|
uint64_t flags) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
}// namespace filament::backend
|
}// namespace filament::backend
|
||||||
|
|||||||
@@ -1408,8 +1408,8 @@ void MetalDriver::setRenderPrimitiveBuffer(Handle<HwRenderPrimitive> rph, Primit
|
|||||||
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
|
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
|
||||||
auto vertexBuffer = handle_cast<MetalVertexBuffer>(vbh);
|
auto vertexBuffer = handle_cast<MetalVertexBuffer>(vbh);
|
||||||
auto indexBuffer = handle_cast<MetalIndexBuffer>(ibh);
|
auto indexBuffer = handle_cast<MetalIndexBuffer>(ibh);
|
||||||
primitive->vertexBuffer = vertexBuffer;
|
MetalVertexBufferInfo const* const vbi = handle_cast<MetalVertexBufferInfo>(vertexBuffer->vbih);
|
||||||
primitive->indexBuffer = indexBuffer;
|
primitive->setBuffers(vbi, vertexBuffer, indexBuffer);
|
||||||
primitive->type = pt;
|
primitive->type = pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -194,8 +194,12 @@ struct MetalIndexBuffer : public HwIndexBuffer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct MetalRenderPrimitive : public HwRenderPrimitive {
|
struct MetalRenderPrimitive : public HwRenderPrimitive {
|
||||||
|
MetalRenderPrimitive();
|
||||||
|
void setBuffers(MetalVertexBufferInfo const* const vbi,
|
||||||
|
MetalVertexBuffer* vertexBuffer, MetalIndexBuffer* indexBuffer);
|
||||||
// The pointers to MetalVertexBuffer and MetalIndexBuffer are "weak".
|
// The pointers to MetalVertexBuffer and MetalIndexBuffer are "weak".
|
||||||
// The MetalVertexBuffer and MetalIndexBuffer must outlive the MetalRenderPrimitive.
|
// The MetalVertexBuffer and MetalIndexBuffer must outlive the MetalRenderPrimitive.
|
||||||
|
|
||||||
MetalVertexBuffer* vertexBuffer = nullptr;
|
MetalVertexBuffer* vertexBuffer = nullptr;
|
||||||
MetalIndexBuffer* indexBuffer = nullptr;
|
MetalIndexBuffer* indexBuffer = nullptr;
|
||||||
};
|
};
|
||||||
@@ -376,6 +380,7 @@ public:
|
|||||||
|
|
||||||
math::uint2 getAttachmentSize() noexcept;
|
math::uint2 getAttachmentSize() noexcept;
|
||||||
|
|
||||||
|
bool isDefaultRenderTarget() const { return defaultRenderTarget; }
|
||||||
uint8_t getSamples() const { return samples; }
|
uint8_t getSamples() const { return samples; }
|
||||||
|
|
||||||
Attachment getDrawColorAttachment(size_t index);
|
Attachment getDrawColorAttachment(size_t index);
|
||||||
|
|||||||
@@ -536,6 +536,15 @@ MetalIndexBuffer::MetalIndexBuffer(MetalContext& context, BufferUsage usage, uin
|
|||||||
uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount),
|
uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount),
|
||||||
buffer(context, BufferObjectBinding::VERTEX, usage, elementSize * indexCount, true) { }
|
buffer(context, BufferObjectBinding::VERTEX, usage, elementSize * indexCount, true) { }
|
||||||
|
|
||||||
|
MetalRenderPrimitive::MetalRenderPrimitive() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetalRenderPrimitive::setBuffers(MetalVertexBufferInfo const* const vbi,
|
||||||
|
MetalVertexBuffer* vertexBuffer, MetalIndexBuffer* indexBuffer) {
|
||||||
|
this->vertexBuffer = vertexBuffer;
|
||||||
|
this->indexBuffer = indexBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
MetalProgram::MetalProgram(MetalContext& context, Program&& program) noexcept
|
MetalProgram::MetalProgram(MetalContext& context, Program&& program) noexcept
|
||||||
: HwProgram(program.getName()), mContext(context) {
|
: HwProgram(program.getName()), mContext(context) {
|
||||||
mToken = context.shaderCompiler->createProgram(program.getName(), std::move(program));
|
mToken = context.shaderCompiler->createProgram(program.getName(), std::move(program));
|
||||||
|
|||||||
@@ -16,15 +16,9 @@
|
|||||||
|
|
||||||
#include "GLUtils.h"
|
#include "GLUtils.h"
|
||||||
|
|
||||||
#include "private/backend/Driver.h"
|
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
|
||||||
#include <utils/ostream.h>
|
|
||||||
#include <utils/trap.h>
|
#include <utils/trap.h>
|
||||||
|
|
||||||
#include <string_view>
|
#include "private/backend/Driver.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -34,31 +28,38 @@ using namespace utils;
|
|||||||
namespace GLUtils {
|
namespace GLUtils {
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
std::string_view getGLErrorString(GLenum error) noexcept {
|
const char* getGLError(GLenum error) noexcept {
|
||||||
|
const char* string = "unknown";
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case GL_NO_ERROR:
|
case GL_NO_ERROR:
|
||||||
return "GL_NO_ERROR";
|
string = "GL_NO_ERROR";
|
||||||
|
break;
|
||||||
case GL_INVALID_ENUM:
|
case GL_INVALID_ENUM:
|
||||||
return "GL_INVALID_ENUM";
|
string = "GL_INVALID_ENUM";
|
||||||
|
break;
|
||||||
case GL_INVALID_VALUE:
|
case GL_INVALID_VALUE:
|
||||||
return "GL_INVALID_VALUE";
|
string = "GL_INVALID_VALUE";
|
||||||
|
break;
|
||||||
case GL_INVALID_OPERATION:
|
case GL_INVALID_OPERATION:
|
||||||
return "GL_INVALID_OPERATION";
|
string = "GL_INVALID_OPERATION";
|
||||||
|
break;
|
||||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||||
return "GL_INVALID_FRAMEBUFFER_OPERATION";
|
string = "GL_INVALID_FRAMEBUFFER_OPERATION";
|
||||||
|
break;
|
||||||
case GL_OUT_OF_MEMORY:
|
case GL_OUT_OF_MEMORY:
|
||||||
return "GL_OUT_OF_MEMORY";
|
string = "GL_OUT_OF_MEMORY";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return "unknown";
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
GLenum checkGLError(io::ostream& out, const char* function, size_t line) noexcept {
|
GLenum checkGLError(io::ostream& out, const char* function, size_t line) noexcept {
|
||||||
GLenum const error = glGetError();
|
GLenum const error = glGetError();
|
||||||
if (UTILS_VERY_UNLIKELY(error != GL_NO_ERROR)) {
|
if (error != GL_NO_ERROR) {
|
||||||
auto const string = getGLErrorString(error);
|
const char* string = getGLError(error);
|
||||||
out << "OpenGL error " << io::hex << error << " (" << string << ") in \""
|
out << "OpenGL error " << io::hex << error << " (" << string << ") in \""
|
||||||
<< function << "\" at line " << io::dec << line << io::endl;
|
<< function << "\" at line " << io::dec << line << io::endl;
|
||||||
}
|
}
|
||||||
@@ -68,39 +69,46 @@ GLenum checkGLError(io::ostream& out, const char* function, size_t line) noexcep
|
|||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
void assertGLError(io::ostream& out, const char* function, size_t line) noexcept {
|
void assertGLError(io::ostream& out, const char* function, size_t line) noexcept {
|
||||||
GLenum const err = checkGLError(out, function, line);
|
GLenum const err = checkGLError(out, function, line);
|
||||||
if (UTILS_VERY_UNLIKELY(err != GL_NO_ERROR)) {
|
if (err != GL_NO_ERROR) {
|
||||||
debug_trap();
|
debug_trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
std::string_view getFramebufferStatusString(GLenum status) noexcept {
|
const char* getFramebufferStatus(GLenum status) noexcept {
|
||||||
|
const char* string = "unknown";
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case GL_FRAMEBUFFER_COMPLETE:
|
case GL_FRAMEBUFFER_COMPLETE:
|
||||||
return "GL_FRAMEBUFFER_COMPLETE";
|
string = "GL_FRAMEBUFFER_COMPLETE";
|
||||||
|
break;
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||||
return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
|
string = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
|
||||||
|
break;
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||||
return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
|
string = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
|
||||||
|
break;
|
||||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||||
return "GL_FRAMEBUFFER_UNSUPPORTED";
|
string = "GL_FRAMEBUFFER_UNSUPPORTED";
|
||||||
|
break;
|
||||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||||
case GL_FRAMEBUFFER_UNDEFINED:
|
case GL_FRAMEBUFFER_UNDEFINED:
|
||||||
return "GL_FRAMEBUFFER_UNDEFINED";
|
string = "GL_FRAMEBUFFER_UNDEFINED";
|
||||||
|
break;
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||||
return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
|
string = "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return "unknown";
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
GLenum checkFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
|
GLenum checkFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
|
||||||
GLenum const status = glCheckFramebufferStatus(target);
|
GLenum const status = glCheckFramebufferStatus(target);
|
||||||
if (UTILS_VERY_UNLIKELY(status != GL_FRAMEBUFFER_COMPLETE)) {
|
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
auto const string = getFramebufferStatusString(status);
|
const char* string = getFramebufferStatus(status);
|
||||||
out << "OpenGL framebuffer error " << io::hex << status << " (" << string << ") in \""
|
out << "OpenGL framebuffer error " << io::hex << status << " (" << string << ") in \""
|
||||||
<< function << "\" at line " << io::dec << line << io::endl;
|
<< function << "\" at line " << io::dec << line << io::endl;
|
||||||
}
|
}
|
||||||
@@ -110,7 +118,7 @@ GLenum checkFramebufferStatus(io::ostream& out, GLenum target, const char* funct
|
|||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
void assertFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
|
void assertFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
|
||||||
GLenum const status = checkFramebufferStatus(out, target, function, line);
|
GLenum const status = checkFramebufferStatus(out, target, function, line);
|
||||||
if (UTILS_VERY_UNLIKELY(status != GL_FRAMEBUFFER_COMPLETE)) {
|
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
debug_trap();
|
debug_trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,26 +17,29 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
|
#ifndef TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
|
||||||
#define TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
|
#define TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/ostream.h>
|
#include <utils/Log.h>
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "gl_headers.h"
|
#include "gl_headers.h"
|
||||||
|
|
||||||
namespace filament::backend::GLUtils {
|
namespace filament::backend {
|
||||||
|
namespace GLUtils {
|
||||||
|
|
||||||
std::string_view getGLErrorString(GLenum error) noexcept;
|
const char* getGLError(GLenum error) noexcept;
|
||||||
GLenum checkGLError(utils::io::ostream& out, const char* function, size_t line) noexcept;
|
GLenum checkGLError(utils::io::ostream& out, const char* function, size_t line) noexcept;
|
||||||
void assertGLError(utils::io::ostream& out, const char* function, size_t line) noexcept;
|
void assertGLError(utils::io::ostream& out, const char* function, size_t line) noexcept;
|
||||||
|
|
||||||
std::string_view getFramebufferStatusString(GLenum err) noexcept;
|
const char* getFramebufferStatus(GLenum err) noexcept;
|
||||||
GLenum checkFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept;
|
GLenum checkFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept;
|
||||||
void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept;
|
void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept;
|
||||||
|
|
||||||
@@ -50,7 +53,7 @@ void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char*
|
|||||||
# define CHECK_GL_FRAMEBUFFER_STATUS(out, target) { GLUtils::checkFramebufferStatus(out, target, __func__, __LINE__); }
|
# define CHECK_GL_FRAMEBUFFER_STATUS(out, target) { GLUtils::checkFramebufferStatus(out, target, __func__, __LINE__); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr GLuint getComponentCount(ElementType const type) noexcept {
|
constexpr GLuint getComponentCount(ElementType type) noexcept {
|
||||||
using ElementType = ElementType;
|
using ElementType = ElementType;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ElementType::BYTE:
|
case ElementType::BYTE:
|
||||||
@@ -84,29 +87,27 @@ constexpr GLuint getComponentCount(ElementType const type) noexcept {
|
|||||||
case ElementType::USHORT4:
|
case ElementType::USHORT4:
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Our enums to GLenum conversions
|
// Our enums to GLenum conversions
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
constexpr GLbitfield getAttachmentBitfield(TargetBufferFlags const flags) noexcept {
|
constexpr GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexcept {
|
||||||
GLbitfield mask = 0;
|
GLbitfield mask = 0;
|
||||||
if (any(flags & TargetBufferFlags::COLOR_ALL)) {
|
if (any(flags & TargetBufferFlags::COLOR_ALL)) {
|
||||||
mask |= GLbitfield(GL_COLOR_BUFFER_BIT);
|
mask |= (GLbitfield)GL_COLOR_BUFFER_BIT;
|
||||||
}
|
}
|
||||||
if (any(flags & TargetBufferFlags::DEPTH)) {
|
if (any(flags & TargetBufferFlags::DEPTH)) {
|
||||||
mask |= GLbitfield(GL_DEPTH_BUFFER_BIT);
|
mask |= (GLbitfield)GL_DEPTH_BUFFER_BIT;
|
||||||
}
|
}
|
||||||
if (any(flags & TargetBufferFlags::STENCIL)) {
|
if (any(flags & TargetBufferFlags::STENCIL)) {
|
||||||
mask |= GLbitfield(GL_STENCIL_BUFFER_BIT);
|
mask |= (GLbitfield)GL_STENCIL_BUFFER_BIT;
|
||||||
}
|
}
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getBufferUsage(BufferUsage const usage) noexcept {
|
constexpr GLenum getBufferUsage(BufferUsage usage) noexcept {
|
||||||
switch (usage) {
|
switch (usage) {
|
||||||
case BufferUsage::STATIC:
|
case BufferUsage::STATIC:
|
||||||
return GL_STATIC_DRAW;
|
return GL_STATIC_DRAW;
|
||||||
@@ -115,7 +116,7 @@ constexpr GLenum getBufferUsage(BufferUsage const usage) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getBufferBindingType(BufferObjectBinding const bindingType) noexcept {
|
constexpr GLenum getBufferBindingType(BufferObjectBinding bindingType) noexcept {
|
||||||
switch (bindingType) {
|
switch (bindingType) {
|
||||||
case BufferObjectBinding::VERTEX:
|
case BufferObjectBinding::VERTEX:
|
||||||
return GL_ARRAY_BUFFER;
|
return GL_ARRAY_BUFFER;
|
||||||
@@ -134,15 +135,13 @@ constexpr GLenum getBufferBindingType(BufferObjectBinding const bindingType) noe
|
|||||||
return 0x90D2; // just to return something
|
return 0x90D2; // just to return something
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_ARRAY_BUFFER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLboolean getNormalization(bool const normalized) noexcept {
|
constexpr GLboolean getNormalization(bool normalized) noexcept {
|
||||||
return GLboolean(normalized ? GL_TRUE : GL_FALSE);
|
return GLboolean(normalized ? GL_TRUE : GL_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getComponentType(ElementType const type) noexcept {
|
constexpr GLenum getComponentType(ElementType type) noexcept {
|
||||||
using ElementType = ElementType;
|
using ElementType = ElementType;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ElementType::BYTE:
|
case ElementType::BYTE:
|
||||||
@@ -185,11 +184,9 @@ constexpr GLenum getComponentType(ElementType const type) noexcept {
|
|||||||
return GL_HALF_FLOAT_OES;
|
return GL_HALF_FLOAT_OES;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_INT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getTextureTargetNotExternal(SamplerType const target) noexcept {
|
constexpr GLenum getTextureTargetNotExternal(SamplerType target) noexcept {
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case SamplerType::SAMPLER_2D:
|
case SamplerType::SAMPLER_2D:
|
||||||
return GL_TEXTURE_2D;
|
return GL_TEXTURE_2D;
|
||||||
@@ -205,16 +202,14 @@ constexpr GLenum getTextureTargetNotExternal(SamplerType const target) noexcept
|
|||||||
// we should never be here
|
// we should never be here
|
||||||
return GL_TEXTURE_2D;
|
return GL_TEXTURE_2D;
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_TEXTURE_2D;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getCubemapTarget(uint16_t const layer) noexcept {
|
constexpr GLenum getCubemapTarget(uint16_t layer) noexcept {
|
||||||
assert_invariant(layer <= 5);
|
assert_invariant(layer <= 5);
|
||||||
return GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
|
return GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getWrapMode(SamplerWrapMode const mode) noexcept {
|
constexpr GLenum getWrapMode(SamplerWrapMode mode) noexcept {
|
||||||
using SamplerWrapMode = SamplerWrapMode;
|
using SamplerWrapMode = SamplerWrapMode;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case SamplerWrapMode::REPEAT:
|
case SamplerWrapMode::REPEAT:
|
||||||
@@ -224,8 +219,6 @@ constexpr GLenum getWrapMode(SamplerWrapMode const mode) noexcept {
|
|||||||
case SamplerWrapMode::MIRRORED_REPEAT:
|
case SamplerWrapMode::MIRRORED_REPEAT:
|
||||||
return GL_MIRRORED_REPEAT;
|
return GL_MIRRORED_REPEAT;
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_CLAMP_TO_EDGE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getTextureFilter(SamplerMinFilter filter) noexcept {
|
constexpr GLenum getTextureFilter(SamplerMinFilter filter) noexcept {
|
||||||
@@ -241,8 +234,6 @@ constexpr GLenum getTextureFilter(SamplerMinFilter filter) noexcept {
|
|||||||
return GL_NEAREST_MIPMAP_NEAREST
|
return GL_NEAREST_MIPMAP_NEAREST
|
||||||
- GLenum(SamplerMinFilter::NEAREST_MIPMAP_NEAREST) + GLenum(filter);
|
- GLenum(SamplerMinFilter::NEAREST_MIPMAP_NEAREST) + GLenum(filter);
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_NEAREST;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getTextureFilter(SamplerMagFilter filter) noexcept {
|
constexpr GLenum getTextureFilter(SamplerMagFilter filter) noexcept {
|
||||||
@@ -250,7 +241,7 @@ constexpr GLenum getTextureFilter(SamplerMagFilter filter) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
constexpr GLenum getBlendEquationMode(BlendEquation const mode) noexcept {
|
constexpr GLenum getBlendEquationMode(BlendEquation mode) noexcept {
|
||||||
using BlendEquation = BlendEquation;
|
using BlendEquation = BlendEquation;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case BlendEquation::ADD: return GL_FUNC_ADD;
|
case BlendEquation::ADD: return GL_FUNC_ADD;
|
||||||
@@ -259,11 +250,9 @@ constexpr GLenum getBlendEquationMode(BlendEquation const mode) noexcept {
|
|||||||
case BlendEquation::MIN: return GL_MIN;
|
case BlendEquation::MIN: return GL_MIN;
|
||||||
case BlendEquation::MAX: return GL_MAX;
|
case BlendEquation::MAX: return GL_MAX;
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_FUNC_ADD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getBlendFunctionMode(BlendFunction const mode) noexcept {
|
constexpr GLenum getBlendFunctionMode(BlendFunction mode) noexcept {
|
||||||
using BlendFunction = BlendFunction;
|
using BlendFunction = BlendFunction;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case BlendFunction::ZERO: return GL_ZERO;
|
case BlendFunction::ZERO: return GL_ZERO;
|
||||||
@@ -278,11 +267,9 @@ constexpr GLenum getBlendFunctionMode(BlendFunction const mode) noexcept {
|
|||||||
case BlendFunction::ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
|
case BlendFunction::ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
|
||||||
case BlendFunction::SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE;
|
case BlendFunction::SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE;
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_ONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getCompareFunc(SamplerCompareFunc const func) noexcept {
|
constexpr GLenum getCompareFunc(SamplerCompareFunc func) noexcept {
|
||||||
switch (func) {
|
switch (func) {
|
||||||
case SamplerCompareFunc::LE: return GL_LEQUAL;
|
case SamplerCompareFunc::LE: return GL_LEQUAL;
|
||||||
case SamplerCompareFunc::GE: return GL_GEQUAL;
|
case SamplerCompareFunc::GE: return GL_GEQUAL;
|
||||||
@@ -293,30 +280,28 @@ constexpr GLenum getCompareFunc(SamplerCompareFunc const func) noexcept {
|
|||||||
case SamplerCompareFunc::A: return GL_ALWAYS;
|
case SamplerCompareFunc::A: return GL_ALWAYS;
|
||||||
case SamplerCompareFunc::N: return GL_NEVER;
|
case SamplerCompareFunc::N: return GL_NEVER;
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_LEQUAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||||
constexpr GLenum getTextureCompareMode(SamplerCompareMode const mode) noexcept {
|
constexpr GLenum getTextureCompareMode(SamplerCompareMode mode) noexcept {
|
||||||
return mode == SamplerCompareMode::NONE ?
|
return mode == SamplerCompareMode::NONE ?
|
||||||
GL_NONE : GL_COMPARE_REF_TO_TEXTURE;
|
GL_NONE : GL_COMPARE_REF_TO_TEXTURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getTextureCompareFunc(SamplerCompareFunc const func) noexcept {
|
constexpr GLenum getTextureCompareFunc(SamplerCompareFunc func) noexcept {
|
||||||
return getCompareFunc(func);
|
return getCompareFunc(func);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr GLenum getDepthFunc(SamplerCompareFunc const func) noexcept {
|
constexpr GLenum getDepthFunc(SamplerCompareFunc func) noexcept {
|
||||||
return getCompareFunc(func);
|
return getCompareFunc(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getStencilFunc(SamplerCompareFunc const func) noexcept {
|
constexpr GLenum getStencilFunc(SamplerCompareFunc func) noexcept {
|
||||||
return getCompareFunc(func);
|
return getCompareFunc(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getStencilOp(StencilOperation const op) noexcept {
|
constexpr GLenum getStencilOp(StencilOperation op) noexcept {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case StencilOperation::KEEP: return GL_KEEP;
|
case StencilOperation::KEEP: return GL_KEEP;
|
||||||
case StencilOperation::ZERO: return GL_ZERO;
|
case StencilOperation::ZERO: return GL_ZERO;
|
||||||
@@ -327,11 +312,9 @@ constexpr GLenum getStencilOp(StencilOperation const op) noexcept {
|
|||||||
case StencilOperation::DECR_WRAP: return GL_DECR_WRAP;
|
case StencilOperation::DECR_WRAP: return GL_DECR_WRAP;
|
||||||
case StencilOperation::INVERT: return GL_INVERT;
|
case StencilOperation::INVERT: return GL_INVERT;
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_KEEP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getFormat(PixelDataFormat const format) noexcept {
|
constexpr GLenum getFormat(PixelDataFormat format) noexcept {
|
||||||
using PixelDataFormat = PixelDataFormat;
|
using PixelDataFormat = PixelDataFormat;
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case PixelDataFormat::RGB: return GL_RGB;
|
case PixelDataFormat::RGB: return GL_RGB;
|
||||||
@@ -353,11 +336,9 @@ constexpr GLenum getFormat(PixelDataFormat const format) noexcept {
|
|||||||
default: return GL_NONE;
|
default: return GL_NONE;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_RGBA;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr GLenum getType(PixelDataType const type) noexcept {
|
constexpr GLenum getType(PixelDataType type) noexcept {
|
||||||
using PixelDataType = PixelDataType;
|
using PixelDataType = PixelDataType;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PixelDataType::UBYTE: return GL_UNSIGNED_BYTE;
|
case PixelDataType::UBYTE: return GL_UNSIGNED_BYTE;
|
||||||
@@ -379,12 +360,10 @@ constexpr GLenum getType(PixelDataType const type) noexcept {
|
|||||||
default: return GL_NONE;
|
default: return GL_NONE;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_UNSIGNED_INT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
|
#if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
|
||||||
constexpr GLenum getSwizzleChannel(TextureSwizzle const c) noexcept {
|
constexpr GLenum getSwizzleChannel(TextureSwizzle c) noexcept {
|
||||||
using TextureSwizzle = TextureSwizzle;
|
using TextureSwizzle = TextureSwizzle;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case TextureSwizzle::SUBSTITUTE_ZERO: return GL_ZERO;
|
case TextureSwizzle::SUBSTITUTE_ZERO: return GL_ZERO;
|
||||||
@@ -394,12 +373,10 @@ constexpr GLenum getSwizzleChannel(TextureSwizzle const c) noexcept {
|
|||||||
case TextureSwizzle::CHANNEL_2: return GL_BLUE;
|
case TextureSwizzle::CHANNEL_2: return GL_BLUE;
|
||||||
case TextureSwizzle::CHANNEL_3: return GL_ALPHA;
|
case TextureSwizzle::CHANNEL_3: return GL_ALPHA;
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_RED;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr GLenum getCullingMode(CullingMode const mode) noexcept {
|
constexpr GLenum getCullingMode(CullingMode mode) noexcept {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case CullingMode::NONE:
|
case CullingMode::NONE:
|
||||||
// should never happen
|
// should never happen
|
||||||
@@ -411,13 +388,11 @@ constexpr GLenum getCullingMode(CullingMode const mode) noexcept {
|
|||||||
case CullingMode::FRONT_AND_BACK:
|
case CullingMode::FRONT_AND_BACK:
|
||||||
return GL_FRONT_AND_BACK;
|
return GL_FRONT_AND_BACK;
|
||||||
}
|
}
|
||||||
// should never happen
|
|
||||||
return GL_FRONT_AND_BACK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES2 supported internal formats for texturing and how they map to a format/type
|
// ES2 supported internal formats for texturing and how they map to a format/type
|
||||||
constexpr std::pair<GLenum, GLenum> textureFormatToFormatAndType(
|
constexpr std::pair<GLenum, GLenum> textureFormatToFormatAndType(
|
||||||
TextureFormat const format) noexcept {
|
TextureFormat format) noexcept {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case TextureFormat::R8: return { 0x1909 /*GL_LUMINANCE*/, GL_UNSIGNED_BYTE };
|
case TextureFormat::R8: return { 0x1909 /*GL_LUMINANCE*/, GL_UNSIGNED_BYTE };
|
||||||
case TextureFormat::RGB8: return { GL_RGB, GL_UNSIGNED_BYTE };
|
case TextureFormat::RGB8: return { GL_RGB, GL_UNSIGNED_BYTE };
|
||||||
@@ -438,7 +413,7 @@ constexpr std::pair<GLenum, GLenum> textureFormatToFormatAndType(
|
|||||||
// clang loses it on this one, and generates a huge jump table when
|
// clang loses it on this one, and generates a huge jump table when
|
||||||
// inlined. So we don't mark it as inline (only constexpr) which solves the problem,
|
// inlined. So we don't mark it as inline (only constexpr) which solves the problem,
|
||||||
// strangely, when not inlined, clang simply generates an array lookup.
|
// strangely, when not inlined, clang simply generates an array lookup.
|
||||||
constexpr /* inline */ GLenum getInternalFormat(TextureFormat const format) noexcept {
|
constexpr /* inline */ GLenum getInternalFormat(TextureFormat format) noexcept {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
|
|
||||||
/* Formats supported by our ES2 implementations */
|
/* Formats supported by our ES2 implementations */
|
||||||
@@ -686,7 +661,7 @@ public:
|
|||||||
|
|
||||||
unordered_string_set split(const char* extensions) noexcept;
|
unordered_string_set split(const char* extensions) noexcept;
|
||||||
|
|
||||||
} // namespace filament::backend::GLUtils
|
} // namespace GLUtils
|
||||||
|
} // namespace filament::backend
|
||||||
|
|
||||||
#endif // TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
|
#endif // TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
|
||||||
|
|||||||
@@ -2098,7 +2098,6 @@ void OpenGLDriver::setAcquiredImage(Handle<HwStream> sh, void* hwbuffer, const m
|
|||||||
|
|
||||||
glstream->user_thread.pending = mPlatform.transformAcquiredImage({
|
glstream->user_thread.pending = mPlatform.transformAcquiredImage({
|
||||||
hwbuffer, cb, userData, handler });
|
hwbuffer, cb, userData, handler });
|
||||||
glstream->user_thread.transform = transform;
|
|
||||||
|
|
||||||
if (glstream->user_thread.pending.image != nullptr) {
|
if (glstream->user_thread.pending.image != nullptr) {
|
||||||
// If there's no pending image, do nothing. Note that GL_OES_EGL_image does not let you pass
|
// If there's no pending image, do nothing. Note that GL_OES_EGL_image does not let you pass
|
||||||
|
|||||||
@@ -17,10 +17,8 @@
|
|||||||
#define COREVIDEO_SILENCE_GL_DEPRECATION
|
#define COREVIDEO_SILENCE_GL_DEPRECATION
|
||||||
|
|
||||||
#include "CocoaExternalImage.h"
|
#include "CocoaExternalImage.h"
|
||||||
#include "../GLUtils.h"
|
|
||||||
|
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include <utils/Log.h>
|
#include "../GLUtils.h"
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/Log.h>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
|
|||||||
@@ -295,8 +295,6 @@ VulkanCommandBuffer& CommandBufferPool::getRecording() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CommandBufferPool::gc() {
|
void CommandBufferPool::gc() {
|
||||||
FVK_SYSTRACE_CONTEXT();
|
|
||||||
FVK_SYSTRACE_START("CommandBufferPool::gc");
|
|
||||||
ActiveBuffers reclaimed;
|
ActiveBuffers reclaimed;
|
||||||
mSubmitted.forEachSetBit([this,&reclaimed] (size_t index) {
|
mSubmitted.forEachSetBit([this,&reclaimed] (size_t index) {
|
||||||
auto& buffer = mBuffers[index];
|
auto& buffer = mBuffers[index];
|
||||||
@@ -306,7 +304,6 @@ void CommandBufferPool::gc() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
mSubmitted &= ~reclaimed;
|
mSubmitted &= ~reclaimed;
|
||||||
FVK_SYSTRACE_END();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBufferPool::update() {
|
void CommandBufferPool::update() {
|
||||||
@@ -336,9 +333,7 @@ void CommandBufferPool::wait() {
|
|||||||
mSubmitted.forEachSetBit([this, &count, &fences] (size_t index) {
|
mSubmitted.forEachSetBit([this, &count, &fences] (size_t index) {
|
||||||
fences[count++] = mBuffers[index]->getVkFence();
|
fences[count++] = mBuffers[index]->getVkFence();
|
||||||
});
|
});
|
||||||
if (count) {
|
vkWaitForFences(mDevice, count, fences, VK_TRUE, UINT64_MAX);
|
||||||
vkWaitForFences(mDevice, count, fences, VK_TRUE, UINT64_MAX);
|
|
||||||
}
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ namespace filament::backend {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using DescriptorCount = VulkanDescriptorSetLayout::Count;
|
||||||
using DescriptorSetLayoutArray = VulkanDescriptorSetCache::DescriptorSetLayoutArray;
|
using DescriptorSetLayoutArray = VulkanDescriptorSetCache::DescriptorSetLayoutArray;
|
||||||
using DescriptorCount = VulkanDescriptorSetCache::DescriptorCount;
|
|
||||||
|
|
||||||
// We create a pool for each layout as defined by the number of descriptors of each type. For
|
// We create a pool for each layout as defined by the number of descriptors of each type. For
|
||||||
// example, a layout of
|
// example, a layout of
|
||||||
@@ -203,10 +203,11 @@ public:
|
|||||||
DescriptorInfinitePool(VkDevice device)
|
DescriptorInfinitePool(VkDevice device)
|
||||||
: mDevice(device) {}
|
: mDevice(device) {}
|
||||||
|
|
||||||
VkDescriptorSet obtainSet(DescriptorCount const& count, VkDescriptorSetLayout vklayout) {
|
VkDescriptorSet obtainSet(fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
||||||
|
auto const vklayout = layout->getVkLayout();
|
||||||
DescriptorPool* sameTypePool = nullptr;
|
DescriptorPool* sameTypePool = nullptr;
|
||||||
for (auto& pool: mPools) {
|
for (auto& pool: mPools) {
|
||||||
if (!pool->canAllocate(count)) {
|
if (!pool->canAllocate(layout->count)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (auto set = pool->obtainSet(vklayout); set != VK_NULL_HANDLE) {
|
if (auto set = pool->obtainSet(vklayout); set != VK_NULL_HANDLE) {
|
||||||
@@ -224,7 +225,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We need to increase the set of pools by one.
|
// We need to increase the set of pools by one.
|
||||||
mPools.push_back(std::make_unique<DescriptorPool>(mDevice, count, capacity));
|
mPools.push_back(std::make_unique<DescriptorPool>(mDevice,
|
||||||
|
DescriptorCount::fromLayoutBitmask(layout->bitmask), capacity));
|
||||||
auto& pool = mPools.back();
|
auto& pool = mPools.back();
|
||||||
auto ret = pool->obtainSet(vklayout);
|
auto ret = pool->obtainSet(vklayout);
|
||||||
assert_invariant(ret != VK_NULL_HANDLE && "failed to obtain a set?");
|
assert_invariant(ret != VK_NULL_HANDLE && "failed to obtain a set?");
|
||||||
@@ -274,36 +276,39 @@ void VulkanDescriptorSetCache::unbind(uint8_t setIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::commit(VulkanCommandBuffer* commands,
|
void VulkanDescriptorSetCache::commit(VulkanCommandBuffer* commands,
|
||||||
VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask const& useExternalSamplers,
|
VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask const& setMask) {
|
||||||
fvkutils::DescriptorSetMask const& setMask) {
|
|
||||||
// setMask indicates the set of descriptor sets the driver wants to bind, curMask is the
|
// setMask indicates the set of descriptor sets the driver wants to bind, curMask is the
|
||||||
// actual set of sets that *needs* to be bound.
|
// actual set of sets that *needs* to be bound.
|
||||||
fvkutils::DescriptorSetMask curMask = setMask;
|
fvkutils::DescriptorSetMask curMask = setMask;
|
||||||
|
|
||||||
auto const& updateSets = mStashedSets;
|
auto& updateSets = mStashedSets;
|
||||||
curMask.forEachSetBit([&](size_t index) {
|
bool const pipelineLayoutIsSame = mLastBoundInfo.pipelineLayout == pipelineLayout;
|
||||||
if (!updateSets[index]) {
|
|
||||||
curMask.unset(index);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (mLastBoundInfo.pipelineLayout == pipelineLayout) {
|
if (pipelineLayoutIsSame) {
|
||||||
auto& lastBoundSets = mLastBoundInfo.boundSets;
|
auto& lastBoundSets = mLastBoundInfo.boundSets;
|
||||||
curMask.forEachSetBit([&](size_t index) {
|
setMask.forEachSetBit([&](size_t index) {
|
||||||
if (updateSets[index] == lastBoundSets[index] && !useExternalSamplers[index]) {
|
if (!updateSets[index] || updateSets[index] == lastBoundSets[index]) {
|
||||||
|
curMask.unset(index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (curMask.none() &&
|
||||||
|
mLastBoundInfo.setMask == setMask && mLastBoundInfo.boundSets == updateSets) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setMask.forEachSetBit([&](size_t index) {
|
||||||
|
if (!updateSets[index]) {
|
||||||
curMask.unset(index);
|
curMask.unset(index);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
curMask.forEachSetBit([&](size_t index) {
|
curMask.forEachSetBit([&updateSets, commands, pipelineLayout](size_t index) {
|
||||||
// This code actually binds the descriptor sets.
|
// This code actually binds the descriptor sets.
|
||||||
auto set = updateSets[index];
|
auto set = updateSets[index];
|
||||||
VkCommandBuffer const cmdbuffer = commands->buffer();
|
VkCommandBuffer const cmdbuffer = commands->buffer();
|
||||||
VkDescriptorSet vkset = useExternalSamplers[index] ? set->getExternalSamplerVkSet() :
|
|
||||||
set->getVkSet();
|
|
||||||
vkCmdBindDescriptorSets(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, index,
|
vkCmdBindDescriptorSets(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, index,
|
||||||
1, &vkset, set->uniqueDynamicUboCount, set->getOffsets()->data());
|
1, &set->getVkSet(), set->uniqueDynamicUboCount, set->getOffsets()->data());
|
||||||
commands->acquire(set);
|
commands->acquire(set);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -329,7 +334,7 @@ void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescri
|
|||||||
if (set->dynamicUboMask.test(binding)) {
|
if (set->dynamicUboMask.test(binding)) {
|
||||||
type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||||
}
|
}
|
||||||
VkWriteDescriptorSet descriptorWrite = {
|
VkWriteDescriptorSet const descriptorWrite = {
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.dstSet = set->getVkSet(),
|
.dstSet = set->getVkSet(),
|
||||||
.dstBinding = binding,
|
.dstBinding = binding,
|
||||||
@@ -338,17 +343,12 @@ void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescri
|
|||||||
.pBufferInfo = &info,
|
.pBufferInfo = &info,
|
||||||
};
|
};
|
||||||
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
|
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
|
||||||
|
|
||||||
if (auto externalSamplerSet = set->getExternalSamplerVkSet();
|
|
||||||
externalSamplerSet != VK_NULL_HANDLE) {
|
|
||||||
descriptorWrite.dstSet = externalSamplerSet;
|
|
||||||
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
|
|
||||||
}
|
|
||||||
set->acquire(bufferObject);
|
set->acquire(bufferObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::updateSamplerImpl(VkDescriptorSet vkset, uint8_t binding,
|
void VulkanDescriptorSetCache::updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||||
fvkmemory::resource_ptr<VulkanTexture> texture, VkSampler sampler) noexcept {
|
uint8_t binding, fvkmemory::resource_ptr<VulkanTexture> texture,
|
||||||
|
VkSampler sampler) noexcept {
|
||||||
VkImageSubresourceRange range = texture->getPrimaryViewRange();
|
VkImageSubresourceRange range = texture->getPrimaryViewRange();
|
||||||
VkImageViewType const expectedType = texture->getViewType();
|
VkImageViewType const expectedType = texture->getViewType();
|
||||||
if (any(texture->usage & TextureUsage::DEPTH_ATTACHMENT) &&
|
if (any(texture->usage & TextureUsage::DEPTH_ATTACHMENT) &&
|
||||||
@@ -364,29 +364,16 @@ void VulkanDescriptorSetCache::updateSamplerImpl(VkDescriptorSet vkset, uint8_t
|
|||||||
.imageLayout = fvkutils::getVkLayout(texture->getDefaultLayout()),
|
.imageLayout = fvkutils::getVkLayout(texture->getDefaultLayout()),
|
||||||
};
|
};
|
||||||
|
|
||||||
VkWriteDescriptorSet descriptorWrite = {
|
VkWriteDescriptorSet const descriptorWrite = {
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.dstSet = vkset,
|
.dstSet = set->getVkSet(),
|
||||||
.dstBinding = binding,
|
.dstBinding = binding,
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
.pImageInfo = &info,
|
.pImageInfo = &info,
|
||||||
};
|
};
|
||||||
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
|
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
|
||||||
uint8_t binding, fvkmemory::resource_ptr<VulkanTexture> texture,
|
|
||||||
VkSampler sampler) noexcept {
|
|
||||||
updateSamplerImpl(set->getVkSet(), binding, texture, sampler);
|
|
||||||
set->acquire(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::updateSamplerForExternalSamplerSet(
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding,
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> texture) noexcept {
|
|
||||||
updateSamplerImpl(set->getExternalSamplerVkSet(), binding, texture, VK_NULL_HANDLE);
|
|
||||||
set->acquire(texture);
|
set->acquire(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,32 +383,32 @@ void VulkanDescriptorSetCache::updateInputAttachment(
|
|||||||
// TOOD: fill this in.
|
// TOOD: fill this in.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetCache::createSet(
|
fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetCache::createSet(
|
||||||
Handle<HwDescriptorSet> handle, fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
Handle<HwDescriptorSet> handle, fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
||||||
auto const vkSet = mDescriptorPool->obtainSet(layout->count, layout->getVkLayout());
|
auto const vkSet = getVkSet(layout);
|
||||||
auto const& count = layout->count;
|
auto const& count = layout->count;
|
||||||
auto const vklayout = layout->getVkLayout();
|
auto const vklayout = layout->getVkLayout();
|
||||||
auto set = fvkmemory::resource_ptr<VulkanDescriptorSet>::make(
|
auto set = fvkmemory::resource_ptr<VulkanDescriptorSet>::make(mResourceManager, handle,
|
||||||
mResourceManager, handle, layout->bitmask.dynamicUbo, layout->count.dynamicUbo,
|
layout->bitmask.dynamicUbo, layout->count.dynamicUbo,
|
||||||
[vkSet, count, vklayout, this](
|
[vkSet, count, vklayout, this](VulkanDescriptorSet*) {
|
||||||
VulkanDescriptorSet*) { this->manualRecycle(count, vklayout, vkSet); },
|
// Note that mDescriptorPool could be gone due to terminate (when the backend shuts
|
||||||
vkSet);
|
// down).
|
||||||
|
if (mDescriptorPool) {
|
||||||
|
mDescriptorPool->recycle(count, vklayout, vkSet);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
set->setVkSet(vkSet);
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSet VulkanDescriptorSetCache::getVkSet(DescriptorCount const& count,
|
VkDescriptorSet VulkanDescriptorSetCache::getVkSet(
|
||||||
VkDescriptorSetLayout vklayout) {
|
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
||||||
return mDescriptorPool->obtainSet(count, vklayout);
|
return mDescriptorPool->obtainSet(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::manualRecycle(VulkanDescriptorSetLayout::Count const& count,
|
void VulkanDescriptorSetCache::manualRecyle(VulkanDescriptorSetLayout::Count const& count,
|
||||||
VkDescriptorSetLayout vklayout, VkDescriptorSet vkSet) {
|
VkDescriptorSetLayout vklayout, VkDescriptorSet vkSet) {
|
||||||
// Note that mDescriptorPool could be gone due to terminate (when the backend shuts
|
mDescriptorPool->recycle(count, vklayout, vkSet);
|
||||||
// down).
|
|
||||||
if (mDescriptorPool) {
|
|
||||||
mDescriptorPool->recycle(count, vklayout, vkSet);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::gc() { mStashedSets = {}; }
|
void VulkanDescriptorSetCache::gc() { mStashedSets = {}; }
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ public:
|
|||||||
using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
|
using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
|
||||||
using DescriptorSetArray =
|
using DescriptorSetArray =
|
||||||
std::array<fvkmemory::resource_ptr<VulkanDescriptorSet>, UNIQUE_DESCRIPTOR_SET_COUNT>;
|
std::array<fvkmemory::resource_ptr<VulkanDescriptorSet>, UNIQUE_DESCRIPTOR_SET_COUNT>;
|
||||||
using DescriptorCount = VulkanDescriptorSetLayout::Count;
|
|
||||||
|
|
||||||
VulkanDescriptorSetCache(VkDevice device, fvkmemory::ResourceManager* resourceManager);
|
VulkanDescriptorSetCache(VkDevice device, fvkmemory::ResourceManager* resourceManager);
|
||||||
~VulkanDescriptorSetCache();
|
~VulkanDescriptorSetCache();
|
||||||
@@ -57,10 +56,6 @@ public:
|
|||||||
void updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding,
|
void updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding,
|
||||||
fvkmemory::resource_ptr<VulkanTexture> texture, VkSampler sampler) noexcept;
|
fvkmemory::resource_ptr<VulkanTexture> texture, VkSampler sampler) noexcept;
|
||||||
|
|
||||||
void updateSamplerForExternalSamplerSet(fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding,
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> texture) noexcept;
|
|
||||||
|
|
||||||
|
|
||||||
void updateInputAttachment(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
void updateInputAttachment(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||||
VulkanAttachment const& attachment) noexcept;
|
VulkanAttachment const& attachment) noexcept;
|
||||||
|
|
||||||
@@ -70,17 +65,17 @@ public:
|
|||||||
void unbind(uint8_t setIndex);
|
void unbind(uint8_t setIndex);
|
||||||
|
|
||||||
void commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout,
|
void commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout,
|
||||||
fvkutils::DescriptorSetMask const& useExternalSamplerMask,
|
|
||||||
fvkutils::DescriptorSetMask const& setMask);
|
fvkutils::DescriptorSetMask const& setMask);
|
||||||
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> createSet(Handle<HwDescriptorSet> handle,
|
fvkmemory::resource_ptr<VulkanDescriptorSet> createSet(Handle<HwDescriptorSet> handle,
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
|
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
|
||||||
|
|
||||||
// This method is meant to be used with external samplers
|
// This method is only meant to be used with external samplers (or internally within this
|
||||||
VkDescriptorSet getVkSet(DescriptorCount const& count, VkDescriptorSetLayout vklayout);
|
// class).
|
||||||
|
VkDescriptorSet getVkSet(fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
|
||||||
|
|
||||||
// This method is meant to be used with external samplers
|
// This method is only meant to be used with external samplers.
|
||||||
void manualRecycle(VulkanDescriptorSetLayout::Count const& count, VkDescriptorSetLayout vklayout,
|
void manualRecyle(VulkanDescriptorSetLayout::Count const& count, VkDescriptorSetLayout vklayout,
|
||||||
VkDescriptorSet vkSet);
|
VkDescriptorSet vkSet);
|
||||||
|
|
||||||
DescriptorSetArray const& getBoundSets() const { return mStashedSets; }
|
DescriptorSetArray const& getBoundSets() const { return mStashedSets; }
|
||||||
@@ -88,9 +83,6 @@ public:
|
|||||||
void gc();
|
void gc();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateSamplerImpl(VkDescriptorSet set, uint8_t binding,
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> texture, VkSampler sampler) noexcept;
|
|
||||||
|
|
||||||
class DescriptorInfinitePool;
|
class DescriptorInfinitePool;
|
||||||
|
|
||||||
VkDevice mDevice;
|
VkDevice mDevice;
|
||||||
|
|||||||
@@ -127,7 +127,6 @@ void VulkanDescriptorSetLayoutCache::terminate() noexcept {
|
|||||||
|
|
||||||
VkDescriptorSetLayout VulkanDescriptorSetLayoutCache::getVkLayout(
|
VkDescriptorSetLayout VulkanDescriptorSetLayoutCache::getVkLayout(
|
||||||
VulkanDescriptorSetLayout::Bitmask const& bitmasks,
|
VulkanDescriptorSetLayout::Bitmask const& bitmasks,
|
||||||
fvkutils::SamplerBitmask externalSamplers,
|
|
||||||
utils::FixedCapacityVector<VkSampler> immutableSamplers) {
|
utils::FixedCapacityVector<VkSampler> immutableSamplers) {
|
||||||
LayoutKey key = {
|
LayoutKey key = {
|
||||||
.bitmask = bitmasks,
|
.bitmask = bitmasks,
|
||||||
@@ -142,7 +141,7 @@ VkDescriptorSetLayout VulkanDescriptorSetLayoutCache::getVkLayout(
|
|||||||
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
||||||
bitmasks.dynamicUbo);
|
bitmasks.dynamicUbo);
|
||||||
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bitmasks.ubo);
|
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bitmasks.ubo);
|
||||||
count += appendSamplerBindings(&toBind[count], bitmasks.sampler, externalSamplers,
|
count += appendSamplerBindings(&toBind[count], bitmasks.sampler, bitmasks.externalSampler,
|
||||||
immutableSamplers);
|
immutableSamplers);
|
||||||
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
||||||
bitmasks.inputAttachment);
|
bitmasks.inputAttachment);
|
||||||
@@ -161,9 +160,9 @@ VkDescriptorSetLayout VulkanDescriptorSetLayoutCache::getVkLayout(
|
|||||||
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> VulkanDescriptorSetLayoutCache::createLayout(
|
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> VulkanDescriptorSetLayoutCache::createLayout(
|
||||||
Handle<HwDescriptorSetLayout> handle, backend::DescriptorSetLayout&& info) {
|
Handle<HwDescriptorSetLayout> handle, backend::DescriptorSetLayout&& info) {
|
||||||
BitmaskGroup maskGroup = VulkanDescriptorSetLayout::Bitmask::fromLayoutDescription(info);
|
|
||||||
auto layout = fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::make(mResourceManager, handle,
|
auto layout = fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::make(mResourceManager, handle,
|
||||||
std::move(info), getVkLayout(maskGroup, maskGroup.externalSampler));
|
info);
|
||||||
|
layout->setVkLayout(getVkLayout(layout->bitmask));
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ public:
|
|||||||
|
|
||||||
// This method is meant to be used with external samplers
|
// This method is meant to be used with external samplers
|
||||||
VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout::Bitmask const& bitmasks,
|
VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout::Bitmask const& bitmasks,
|
||||||
fvkutils::SamplerBitmask externalSamplers,
|
|
||||||
utils::FixedCapacityVector<VkSampler> immutableSamplers = {});
|
utils::FixedCapacityVector<VkSampler> immutableSamplers = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "vulkan/memory/ResourcePointer.h"
|
#include "vulkan/memory/ResourcePointer.h"
|
||||||
#include "vulkan/utils/Conversion.h"
|
#include "vulkan/utils/Conversion.h"
|
||||||
#include "vulkan/utils/Definitions.h"
|
#include "vulkan/utils/Definitions.h"
|
||||||
|
#include "vulkan/vulkan_core.h"
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/platforms/VulkanPlatform.h>
|
#include <backend/platforms/VulkanPlatform.h>
|
||||||
@@ -197,9 +198,11 @@ Dispatcher VulkanDriver::getDispatcher() const noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& context,
|
VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& context,
|
||||||
Platform::DriverConfig const& driverConfig)
|
Platform::DriverConfig const& driverConfig) noexcept
|
||||||
: mPlatform(platform),
|
: mPlatform(platform),
|
||||||
mResourceManager(driverConfig.handleArenaSize, driverConfig.disableHandleUseAfterFreeCheck,
|
mResourceManager(
|
||||||
|
driverConfig.handleArenaSize,
|
||||||
|
driverConfig.disableHandleUseAfterFreeCheck,
|
||||||
driverConfig.disableHeapHandleTags),
|
driverConfig.disableHeapHandleTags),
|
||||||
mAllocator(createAllocator(mPlatform->getInstance(), mPlatform->getPhysicalDevice(),
|
mAllocator(createAllocator(mPlatform->getInstance(), mPlatform->getPhysicalDevice(),
|
||||||
mPlatform->getDevice())),
|
mPlatform->getDevice())),
|
||||||
@@ -218,8 +221,6 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
|
|||||||
mDescriptorSetLayoutCache(mPlatform->getDevice(), &mResourceManager),
|
mDescriptorSetLayoutCache(mPlatform->getDevice(), &mResourceManager),
|
||||||
mDescriptorSetCache(mPlatform->getDevice(), &mResourceManager),
|
mDescriptorSetCache(mPlatform->getDevice(), &mResourceManager),
|
||||||
mQueryManager(mPlatform->getDevice()),
|
mQueryManager(mPlatform->getDevice()),
|
||||||
mExternalImageManager(platform, &mSamplerCache, &mYcbcrConversionCache, &mDescriptorSetCache,
|
|
||||||
&mDescriptorSetLayoutCache),
|
|
||||||
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
|
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
|
||||||
mStereoscopicType(driverConfig.stereoscopicType) {
|
mStereoscopicType(driverConfig.stereoscopicType) {
|
||||||
|
|
||||||
@@ -250,7 +251,7 @@ VulkanDriver::~VulkanDriver() noexcept = default;
|
|||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
Driver* VulkanDriver::create(VulkanPlatform* platform, VulkanContext const& context,
|
Driver* VulkanDriver::create(VulkanPlatform* platform, VulkanContext const& context,
|
||||||
Platform::DriverConfig const& driverConfig) {
|
Platform::DriverConfig const& driverConfig) noexcept {
|
||||||
#if 0
|
#if 0
|
||||||
// this is useful for development, but too verbose even for debug builds
|
// this is useful for development, but too verbose even for debug builds
|
||||||
// For reference on a 64-bits machine in Release mode:
|
// For reference on a 64-bits machine in Release mode:
|
||||||
@@ -312,7 +313,7 @@ void VulkanDriver::terminate() {
|
|||||||
|
|
||||||
mCurrentSwapChain = {};
|
mCurrentSwapChain = {};
|
||||||
mDefaultRenderTarget = {};
|
mDefaultRenderTarget = {};
|
||||||
mPipelineState = {};
|
mBoundPipeline = {};
|
||||||
|
|
||||||
mQueryManager.terminate();
|
mQueryManager.terminate();
|
||||||
|
|
||||||
@@ -324,10 +325,6 @@ void VulkanDriver::terminate() {
|
|||||||
|
|
||||||
mCommands.terminate();
|
mCommands.terminate();
|
||||||
|
|
||||||
// Must come before samplerCache, ycbcrConversionCache, descriptorSetCache,
|
|
||||||
// descriptorSetLayoutCache
|
|
||||||
mExternalImageManager.terminate();
|
|
||||||
|
|
||||||
mStagePool.terminate();
|
mStagePool.terminate();
|
||||||
mPipelineCache.terminate();
|
mPipelineCache.terminate();
|
||||||
mFramebufferCache.terminate();
|
mFramebufferCache.terminate();
|
||||||
@@ -384,10 +381,6 @@ void VulkanDriver::beginFrame(int64_t monotonic_clock_ns,
|
|||||||
int64_t refreshIntervalNs, uint32_t frameId) {
|
int64_t refreshIntervalNs, uint32_t frameId) {
|
||||||
FVK_PROFILE_MARKER(PROFILE_NAME_BEGINFRAME);
|
FVK_PROFILE_MARKER(PROFILE_NAME_BEGINFRAME);
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
|
|
||||||
if (mAppState.hasExternalSamplers()) {
|
|
||||||
mExternalImageManager.onBeginFrame();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch, CallbackHandler* handler,
|
void VulkanDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch, CallbackHandler* handler,
|
||||||
@@ -428,17 +421,12 @@ void VulkanDriver::updateDescriptorSetTexture(
|
|||||||
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
||||||
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
|
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
|
||||||
|
|
||||||
if (mExternalImageManager.isExternallySampledTexture(texture)) {
|
// TODO: YcbcrConversion?
|
||||||
mExternalImageManager.bindExternallySampledTexture(set, binding, texture, params);
|
VulkanSamplerCache::Params cacheParams = {
|
||||||
mAppState.hasBoundExternalImages = true;
|
.sampler = params,
|
||||||
} else {
|
};
|
||||||
VulkanSamplerCache::Params cacheParams = {
|
VkSampler const vksampler = mSamplerCache.getSampler(cacheParams);
|
||||||
.sampler = params,
|
mDescriptorSetCache.updateSampler(set, binding, texture, vksampler);
|
||||||
};
|
|
||||||
VkSampler const vksampler = mSamplerCache.getSampler(cacheParams);
|
|
||||||
mDescriptorSetCache.updateSampler(set, binding, texture, vksampler);
|
|
||||||
mExternalImageManager.clearTextureBinding(set, binding);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::flush(int) {
|
void VulkanDriver::flush(int) {
|
||||||
@@ -458,7 +446,6 @@ void VulkanDriver::finish(int dummy) {
|
|||||||
void VulkanDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
void VulkanDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
||||||
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
|
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
|
||||||
PrimitiveType pt) {
|
PrimitiveType pt) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
|
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
|
||||||
auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh);
|
auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh);
|
||||||
auto ptr = resource_ptr<VulkanRenderPrimitive>::make(&mResourceManager, rph, pt, vb, ib);
|
auto ptr = resource_ptr<VulkanRenderPrimitive>::make(&mResourceManager, rph, pt, vb, ib);
|
||||||
@@ -469,14 +456,12 @@ void VulkanDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
|||||||
if (!rph) {
|
if (!rph) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
auto ptr = resource_ptr<VulkanRenderPrimitive>::cast(&mResourceManager, rph);
|
auto ptr = resource_ptr<VulkanRenderPrimitive>::cast(&mResourceManager, rph);
|
||||||
ptr.dec();
|
ptr.dec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
|
void VulkanDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
|
||||||
uint8_t attributeCount, AttributeArray attributes) {
|
uint8_t attributeCount, AttributeArray attributes) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
auto vbi = resource_ptr<VulkanVertexBufferInfo>::make(&mResourceManager, vbih, bufferCount,
|
auto vbi = resource_ptr<VulkanVertexBufferInfo>::make(&mResourceManager, vbih, bufferCount,
|
||||||
attributeCount, attributes);
|
attributeCount, attributes);
|
||||||
vbi.inc();
|
vbi.inc();
|
||||||
@@ -486,14 +471,12 @@ void VulkanDriver::destroyVertexBufferInfo(Handle<HwVertexBufferInfo> vbih) {
|
|||||||
if (!vbih) {
|
if (!vbih) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, vbih);
|
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, vbih);
|
||||||
vbi.dec();
|
vbi.dec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
|
void VulkanDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
|
||||||
Handle<HwVertexBufferInfo> vbih) {
|
Handle<HwVertexBufferInfo> vbih) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, vbih);
|
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, vbih);
|
||||||
auto vb = resource_ptr<VulkanVertexBuffer>::make(&mResourceManager, vbh, mContext, mStagePool,
|
auto vb = resource_ptr<VulkanVertexBuffer>::make(&mResourceManager, vbh, mContext, mStagePool,
|
||||||
vertexCount, vbi);
|
vertexCount, vbi);
|
||||||
@@ -504,14 +487,12 @@ void VulkanDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
|
|||||||
if (!vbh) {
|
if (!vbh) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
|
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
|
||||||
vb.dec();
|
vb.dec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
void VulkanDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
||||||
uint32_t indexCount, BufferUsage usage) {
|
uint32_t indexCount, BufferUsage usage) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
auto elementSize = (uint8_t) getElementTypeSize(elementType);
|
auto elementSize = (uint8_t) getElementTypeSize(elementType);
|
||||||
auto ib = resource_ptr<VulkanIndexBuffer>::make(&mResourceManager, ibh, mAllocator, mStagePool,
|
auto ib = resource_ptr<VulkanIndexBuffer>::make(&mResourceManager, ibh, mAllocator, mStagePool,
|
||||||
elementSize, indexCount);
|
elementSize, indexCount);
|
||||||
@@ -522,14 +503,12 @@ void VulkanDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
|
|||||||
if (!ibh) {
|
if (!ibh) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh);
|
auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh);
|
||||||
ib.dec();
|
ib.dec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||||
BufferObjectBinding bindingType, BufferUsage usage) {
|
BufferObjectBinding bindingType, BufferUsage usage) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
auto bo = resource_ptr<VulkanBufferObject>::make(&mResourceManager, boh, mAllocator, mStagePool,
|
auto bo = resource_ptr<VulkanBufferObject>::make(&mResourceManager, boh, mAllocator, mStagePool,
|
||||||
byteCount, bindingType);
|
byteCount, bindingType);
|
||||||
bo.inc();
|
bo.inc();
|
||||||
@@ -539,7 +518,6 @@ void VulkanDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
|
|||||||
if (!boh) {
|
if (!boh) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
auto bo = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
|
auto bo = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
|
||||||
bo.dec();
|
bo.dec();
|
||||||
}
|
}
|
||||||
@@ -585,48 +563,41 @@ void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::S
|
|||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||||
Platform::ExternalImageHandleRef externalImage) {
|
Platform::ExternalImageHandleRef externalImage) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
auto metadata = mPlatform->extractExternalImageMetadata(externalImage);
|
auto const& metadata = mPlatform->getExternalImageMetadata(externalImage);
|
||||||
|
if (metadata.isProtected) {
|
||||||
|
usage |= backend::TextureUsage::PROTECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageUsageFlags vkUsage = metadata.usage;
|
||||||
|
if (any(usage & TextureUsage::BLIT_SRC)) {
|
||||||
|
vkUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any(usage & (TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE))) {
|
||||||
|
vkUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
assert_invariant(width == metadata.width);
|
assert_invariant(width == metadata.width);
|
||||||
assert_invariant(height == metadata.height);
|
assert_invariant(height == metadata.height);
|
||||||
|
assert_invariant(fvkutils::getVkFormat(format) == metadata.format);
|
||||||
|
|
||||||
// We do not check the format since AHB could return both a known format and an external format.
|
VkMemoryPropertyFlags const requiredMemoryFlags = any(usage & TextureUsage::UPLOADABLE)
|
||||||
// In which case, we choose one or the other, but this choice is not known to the client.
|
? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||||
// Therefore the following lines are commented out.
|
: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||||
// assert_invariant(format == metadata.filamentFormat);
|
uint32_t const memoryTypeIndex =
|
||||||
// assert_invariant(fvkutils::getVkFormat(format) == metadata.format);
|
mContext.selectMemoryType(metadata.memoryTypeBits, requiredMemoryFlags);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(memoryTypeIndex != VK_MAX_MEMORY_TYPES)
|
||||||
|
<< "failed to find a valid memory type for external image memory.";
|
||||||
|
|
||||||
auto imgData = mPlatform->createVkImageFromExternal(externalImage);
|
VkImage vkimg;
|
||||||
|
VkDeviceMemory deviceMemory;
|
||||||
|
std::tie(vkimg, deviceMemory) =
|
||||||
|
mPlatform->createExternalImageData(externalImage, metadata, memoryTypeIndex, vkUsage);
|
||||||
|
|
||||||
assert_invariant(imgData.internal.valid() || imgData.external.valid());
|
|
||||||
|
|
||||||
VkFormat vkformat = metadata.format;
|
|
||||||
VkImage vkimage = VK_NULL_HANDLE;
|
|
||||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
|
||||||
if (imgData.internal.valid()) {
|
|
||||||
metadata.externalFormat = 0;
|
|
||||||
vkimage = imgData.internal.image;
|
|
||||||
memory = imgData.internal.memory;
|
|
||||||
} else { // imgData.external.valid()
|
|
||||||
vkformat = VK_FORMAT_UNDEFINED;
|
|
||||||
vkimage = imgData.external.image;
|
|
||||||
memory = imgData.external.memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerYcbcrConversion const conversion =
|
|
||||||
mExternalImageManager.getVkSamplerYcbcrConversion(metadata);
|
|
||||||
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mContext,
|
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mContext,
|
||||||
mPlatform->getDevice(), mAllocator, &mResourceManager, &mCommands, vkimage, memory,
|
mPlatform->getDevice(), mAllocator, &mResourceManager, &mCommands, vkimg, deviceMemory,
|
||||||
vkformat, conversion, metadata.samples, metadata.width, metadata.height,
|
metadata.format, VK_NULL_HANDLE, metadata.samples, metadata.width, metadata.height,
|
||||||
metadata.layers, usage, mStagePool);
|
metadata.layerCount, usage, mStagePool);
|
||||||
auto& commands = mCommands.get();
|
|
||||||
// Unlike uploaded textures or swapchains, we need to explicit transition this
|
|
||||||
// texture into the read layout.
|
|
||||||
texture->transitionLayout(&commands, texture->getPrimaryViewRange(), VulkanLayout::READ_ONLY);
|
|
||||||
|
|
||||||
if (imgData.external.valid()) {
|
|
||||||
mExternalImageManager.addExternallySampledTexture(texture, externalImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture.inc();
|
texture.inc();
|
||||||
}
|
}
|
||||||
@@ -659,8 +630,6 @@ void VulkanDriver::destroyTexture(Handle<HwTexture> th) {
|
|||||||
}
|
}
|
||||||
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
|
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
|
||||||
texture.dec();
|
texture.dec();
|
||||||
|
|
||||||
mExternalImageManager.removeExternallySampledTexture(texture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
|
void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
|
||||||
@@ -777,7 +746,6 @@ void VulkanDriver::createFenceR(Handle<HwFence> fh, int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
// Running gc() to guard against an edge case where the old swapchains need to have been
|
// Running gc() to guard against an edge case where the old swapchains need to have been
|
||||||
// destroyed before the new swapchain can be created. Otherwise, we would fail
|
// destroyed before the new swapchain can be created. Otherwise, we would fail
|
||||||
// vkCreateSwapchainKHR with VK_ERROR_NATIVE_WINDOW_IN_USE_KHR.
|
// vkCreateSwapchainKHR with VK_ERROR_NATIVE_WINDOW_IN_USE_KHR.
|
||||||
@@ -819,7 +787,6 @@ void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
|||||||
|
|
||||||
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
||||||
backend::DescriptorSetLayout&& info) {
|
backend::DescriptorSetLayout&& info) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
|
||||||
auto layout = mDescriptorSetLayoutCache.createLayout(dslh, std::move(info));
|
auto layout = mDescriptorSetLayoutCache.createLayout(dslh, std::move(info));
|
||||||
layout.inc();
|
layout.inc();
|
||||||
}
|
}
|
||||||
@@ -831,10 +798,6 @@ void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
|||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
|
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
|
||||||
auto set = mDescriptorSetCache.createSet(dsh, layout);
|
auto set = mDescriptorSetCache.createSet(dsh, layout);
|
||||||
set.inc();
|
set.inc();
|
||||||
|
|
||||||
if (layout->hasExternalSamplers()) {
|
|
||||||
mAppState.hasExternalSamplerLayouts = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwVertexBufferInfo> VulkanDriver::createVertexBufferInfoS() noexcept {
|
Handle<HwVertexBufferInfo> VulkanDriver::createVertexBufferInfoS() noexcept {
|
||||||
@@ -959,10 +922,6 @@ void VulkanDriver::destroyDescriptorSetLayout(Handle<HwDescriptorSetLayout> dslh
|
|||||||
void VulkanDriver::destroyDescriptorSet(Handle<HwDescriptorSet> dsh) {
|
void VulkanDriver::destroyDescriptorSet(Handle<HwDescriptorSet> dsh) {
|
||||||
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
||||||
set.dec();
|
set.dec();
|
||||||
|
|
||||||
if (mAppState.hasExternalSamplers() && set->getExternalSamplerVkSet() != VK_NULL_HANDLE) {
|
|
||||||
mExternalImageManager.removeDescriptorSet(set);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwStream> VulkanDriver::createStreamNative(void* nativeStream) {
|
Handle<HwStream> VulkanDriver::createStreamNative(void* nativeStream) {
|
||||||
@@ -1523,6 +1482,7 @@ void VulkanDriver::endRenderPass(int) {
|
|||||||
// pipeline barrier between framebuffer writes and shader reads.
|
// pipeline barrier between framebuffer writes and shader reads.
|
||||||
rt->emitBarriersEndRenderPass(*mCurrentRenderPass.commandBuffer);
|
rt->emitBarriersEndRenderPass(*mCurrentRenderPass.commandBuffer);
|
||||||
|
|
||||||
|
mRenderPassFboInfo = {};
|
||||||
mCurrentRenderPass.renderTarget = {};
|
mCurrentRenderPass.renderTarget = {};
|
||||||
mCurrentRenderPass.renderPass = VK_NULL_HANDLE;
|
mCurrentRenderPass.renderPass = VK_NULL_HANDLE;
|
||||||
|
|
||||||
@@ -1582,10 +1542,10 @@ void VulkanDriver::commit(Handle<HwSwapChain> sch) {
|
|||||||
|
|
||||||
void VulkanDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
|
void VulkanDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
|
||||||
backend::PushConstantVariant value) {
|
backend::PushConstantVariant value) {
|
||||||
assert_invariant(mPipelineState.program && "Expect a program when writing to push constants");
|
assert_invariant(mBoundPipeline.program && "Expect a program when writing to push constants");
|
||||||
assert_invariant(mCurrentRenderPass.commandBuffer && "Should be called within a renderpass");
|
assert_invariant(mCurrentRenderPass.commandBuffer && "Should be called within a renderpass");
|
||||||
mPipelineState.program->writePushConstant(mCurrentRenderPass.commandBuffer->buffer(),
|
mBoundPipeline.program->writePushConstant(mCurrentRenderPass.commandBuffer->buffer(),
|
||||||
mPipelineState.pipelineLayout, stage, index, value);
|
mBoundPipeline.pipelineLayout, stage, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::insertEventMarker(char const* string) {
|
void VulkanDriver::insertEventMarker(char const* string) {
|
||||||
@@ -1764,69 +1724,16 @@ void VulkanDriver::blitDEPRECATED(TargetBufferFlags buffers,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::bindPipeline(PipelineState const& pipelineState) {
|
void VulkanDriver::bindPipeline(PipelineState const& pipelineState) {
|
||||||
// This resets all of the pipeline states; the most relevant (needing reset) is .bindInDraw.
|
|
||||||
mPipelineState = {};
|
|
||||||
|
|
||||||
auto& setLayouts = pipelineState.pipelineLayout.setLayout;
|
|
||||||
DescriptorSetLayoutHandleList layoutHandles;
|
|
||||||
uint8_t layoutCount = 0;
|
|
||||||
std::transform(setLayouts.begin(), setLayouts.end(), layoutHandles.begin(),
|
|
||||||
[&](auto const& handle) -> resource_ptr<VulkanDescriptorSetLayout> {
|
|
||||||
if (!handle) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
layoutCount++;
|
|
||||||
return resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, handle);
|
|
||||||
});
|
|
||||||
|
|
||||||
constexpr uint8_t descriptorSetMaskTable[4] = {0x1, 0x3, 0x7, 0xF};
|
|
||||||
fvkutils::DescriptorSetMask const descriptorSetMask =
|
|
||||||
fvkutils::DescriptorSetMask(descriptorSetMaskTable[layoutCount]);
|
|
||||||
|
|
||||||
if (mAppState.hasExternalSamplers()) {
|
|
||||||
auto const haveExternalSamplers = [&](auto layoutHandle) {
|
|
||||||
if (!layoutHandle) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return layoutHandle->hasExternalSamplers();
|
|
||||||
};
|
|
||||||
if (std::any_of(layoutHandles.begin(), layoutHandles.end(), haveExternalSamplers)) {
|
|
||||||
BindInDrawBundle bundle = {
|
|
||||||
.pipelineState = pipelineState,
|
|
||||||
.dsLayoutHandles = layoutHandles,
|
|
||||||
.descriptorSetMask = descriptorSetMask,
|
|
||||||
};
|
|
||||||
mPipelineState.bindInDraw = { true, bundle };
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The normal, non-external sampler path
|
|
||||||
using VkDescriptorSetLayoutArray = VulkanPipelineLayoutCache::DescriptorSetLayoutArray;
|
|
||||||
VkDescriptorSetLayoutArray vkLayouts;
|
|
||||||
std::transform(layoutHandles.begin(), layoutHandles.end(), vkLayouts.begin(),
|
|
||||||
[](auto const& layout) -> VkDescriptorSetLayout {
|
|
||||||
if (!layout) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
return layout->getVkLayout();
|
|
||||||
});
|
|
||||||
auto program = resource_ptr<VulkanProgram>::cast(&mResourceManager, pipelineState.program);
|
|
||||||
auto pipelineLayout = mPipelineLayoutCache.getLayout(vkLayouts, program);
|
|
||||||
bindPipelineImpl(pipelineState, pipelineLayout, descriptorSetMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDriver::bindPipelineImpl(PipelineState const& pipelineState,
|
|
||||||
VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask descriptorSetMask) {
|
|
||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
auto commands = mCurrentRenderPass.commandBuffer;
|
auto commands = mCurrentRenderPass.commandBuffer;
|
||||||
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager,
|
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager,
|
||||||
pipelineState.vertexBufferInfo);
|
pipelineState.vertexBufferInfo);
|
||||||
|
|
||||||
|
Handle<HwProgram> programHandle = pipelineState.program;
|
||||||
RasterState const& rasterState = pipelineState.rasterState;
|
RasterState const& rasterState = pipelineState.rasterState;
|
||||||
PolygonOffset const& depthOffset = pipelineState.polygonOffset;
|
PolygonOffset const& depthOffset = pipelineState.polygonOffset;
|
||||||
|
|
||||||
auto program = resource_ptr<VulkanProgram>::cast(&mResourceManager, pipelineState.program);
|
auto program = resource_ptr<VulkanProgram>::cast(&mResourceManager, programHandle);
|
||||||
commands->acquire(program);
|
commands->acquire(program);
|
||||||
|
|
||||||
// Update the VK raster state.
|
// Update the VK raster state.
|
||||||
@@ -1868,11 +1775,28 @@ void VulkanDriver::bindPipelineImpl(PipelineState const& pipelineState,
|
|||||||
mPipelineCache.bindPrimitiveTopology(topology);
|
mPipelineCache.bindPrimitiveTopology(topology);
|
||||||
mPipelineCache.bindVertexArray(attribDesc, bufferDesc, vbi->getAttributeCount());
|
mPipelineCache.bindVertexArray(attribDesc, bufferDesc, vbi->getAttributeCount());
|
||||||
|
|
||||||
// Note that we cannot reinit mPipeline because the .bindInDraw metadata that needs to carry
|
auto& setLayouts = pipelineState.pipelineLayout.setLayout;
|
||||||
// over even on bind.
|
VulkanDescriptorSetLayout::DescriptorSetLayoutArray layoutList;
|
||||||
mPipelineState.program = program;
|
uint8_t layoutCount = 0;
|
||||||
mPipelineState.pipelineLayout = pipelineLayout;
|
std::transform(setLayouts.begin(), setLayouts.end(), layoutList.begin(),
|
||||||
mPipelineState.descriptorSetMask = descriptorSetMask;
|
[&](Handle<HwDescriptorSetLayout> handle) -> VkDescriptorSetLayout {
|
||||||
|
if (!handle) {
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
auto layout =
|
||||||
|
resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, handle);
|
||||||
|
layoutCount++;
|
||||||
|
return layout->getVkLayout();
|
||||||
|
});
|
||||||
|
auto pipelineLayout = mPipelineLayoutCache.getLayout(layoutList, program);
|
||||||
|
|
||||||
|
constexpr uint8_t descriptorSetMaskTable[4] = {0x1, 0x3, 0x7, 0xF};
|
||||||
|
|
||||||
|
mBoundPipeline = {
|
||||||
|
.program = program,
|
||||||
|
.pipelineLayout = pipelineLayout,
|
||||||
|
.descriptorSetMask = fvkutils::DescriptorSetMask(descriptorSetMaskTable[layoutCount]),
|
||||||
|
};
|
||||||
|
|
||||||
mPipelineCache.bindLayout(pipelineLayout);
|
mPipelineCache.bindLayout(pipelineLayout);
|
||||||
mPipelineCache.bindPipeline(mCurrentRenderPass.commandBuffer);
|
mPipelineCache.bindPipeline(mCurrentRenderPass.commandBuffer);
|
||||||
@@ -1917,41 +1841,15 @@ void VulkanDriver::bindDescriptorSet(
|
|||||||
void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer();
|
VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer();
|
||||||
auto const& [doBindInDraw, bundle] = mPipelineState.bindInDraw;
|
|
||||||
|
|
||||||
fvkutils::DescriptorSetMask setsWithExternalSamplers = {};
|
mDescriptorSetCache.commit(mCurrentRenderPass.commandBuffer,
|
||||||
if (doBindInDraw) {
|
mBoundPipeline.pipelineLayout,
|
||||||
auto& layoutHandles = bundle.dsLayoutHandles;
|
mBoundPipeline.descriptorSetMask);
|
||||||
setsWithExternalSamplers = mExternalImageManager.prepareBindSets(layoutHandles,
|
|
||||||
mDescriptorSetCache.getBoundSets());
|
|
||||||
|
|
||||||
VulkanDescriptorSetLayout::DescriptorSetLayoutArray vklayouts;
|
|
||||||
for (size_t i = 0; i < layoutHandles.size(); i++) {
|
|
||||||
if (!layoutHandles[i]) {
|
|
||||||
vklayouts[i] = VK_NULL_HANDLE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (setsWithExternalSamplers[i]) {
|
|
||||||
vklayouts[i] = layoutHandles[i]->getExternalSamplerVkLayout();
|
|
||||||
} else {
|
|
||||||
vklayouts[i] = layoutHandles[i]->getVkLayout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto program =
|
|
||||||
resource_ptr<VulkanProgram>::cast(&mResourceManager, bundle.pipelineState.program);
|
|
||||||
VkPipelineLayout const pipelineLayout = mPipelineLayoutCache.getLayout(vklayouts, program);
|
|
||||||
if (pipelineLayout != mPipelineState.pipelineLayout) {
|
|
||||||
bindPipelineImpl(bundle.pipelineState, pipelineLayout, bundle.descriptorSetMask);
|
|
||||||
}
|
|
||||||
mPipelineState.bindInDraw.first = false;
|
|
||||||
}
|
|
||||||
mDescriptorSetCache.commit(mCurrentRenderPass.commandBuffer, mPipelineState.pipelineLayout,
|
|
||||||
setsWithExternalSamplers, mPipelineState.descriptorSetMask);
|
|
||||||
|
|
||||||
// Finally, make the actual draw call. TODO: support subranges
|
// Finally, make the actual draw call. TODO: support subranges
|
||||||
uint32_t const firstIndex = indexOffset;
|
const uint32_t firstIndex = indexOffset;
|
||||||
constexpr int32_t vertexOffset = 0;
|
const int32_t vertexOffset = 0;
|
||||||
constexpr uint32_t firstInstId = 0;
|
const uint32_t firstInstId = 0;
|
||||||
|
|
||||||
vkCmdDrawIndexed(cmdbuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstId);
|
vkCmdDrawIndexed(cmdbuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
#include "VulkanYcbcrConversionCache.h"
|
#include "VulkanYcbcrConversionCache.h"
|
||||||
#include "vulkan/VulkanDescriptorSetCache.h"
|
#include "vulkan/VulkanDescriptorSetCache.h"
|
||||||
#include "vulkan/VulkanDescriptorSetLayoutCache.h"
|
#include "vulkan/VulkanDescriptorSetLayoutCache.h"
|
||||||
#include "vulkan/VulkanExternalImageManager.h"
|
|
||||||
#include "vulkan/VulkanPipelineLayoutCache.h"
|
#include "vulkan/VulkanPipelineLayoutCache.h"
|
||||||
#include "vulkan/memory/ResourceManager.h"
|
#include "vulkan/memory/ResourceManager.h"
|
||||||
#include "vulkan/memory/ResourcePointer.h"
|
#include "vulkan/memory/ResourcePointer.h"
|
||||||
@@ -55,7 +54,7 @@ constexpr uint8_t MAX_RENDERTARGET_ATTACHMENT_TEXTURES =
|
|||||||
class VulkanDriver final : public DriverBase {
|
class VulkanDriver final : public DriverBase {
|
||||||
public:
|
public:
|
||||||
static Driver* create(VulkanPlatform* platform, VulkanContext const& context,
|
static Driver* create(VulkanPlatform* platform, VulkanContext const& context,
|
||||||
Platform::DriverConfig const& driverConfig);
|
Platform::DriverConfig const& driverConfig) noexcept;
|
||||||
|
|
||||||
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
|
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
|
||||||
// Encapsulates the VK_EXT_debug_utils extension. In particular, we use
|
// Encapsulates the VK_EXT_debug_utils extension. In particular, we use
|
||||||
@@ -90,8 +89,8 @@ private:
|
|||||||
void debugCommandBegin(CommandStream* cmds, bool synchronous,
|
void debugCommandBegin(CommandStream* cmds, bool synchronous,
|
||||||
const char* methodName) noexcept override;
|
const char* methodName) noexcept override;
|
||||||
|
|
||||||
VulkanDriver(VulkanPlatform* platform, VulkanContext const& context,
|
inline VulkanDriver(VulkanPlatform* platform, VulkanContext const& context,
|
||||||
Platform::DriverConfig const& driverConfig);
|
Platform::DriverConfig const& driverConfig) noexcept;
|
||||||
|
|
||||||
~VulkanDriver() noexcept override;
|
~VulkanDriver() noexcept override;
|
||||||
|
|
||||||
@@ -120,8 +119,6 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void collectGarbage();
|
void collectGarbage();
|
||||||
void bindPipelineImpl(PipelineState const& pipelineState, VkPipelineLayout pipelineLayout,
|
|
||||||
fvkutils::DescriptorSetMask descriptorSetMask);
|
|
||||||
|
|
||||||
VulkanPlatform* mPlatform = nullptr;
|
VulkanPlatform* mPlatform = nullptr;
|
||||||
fvkmemory::ResourceManager mResourceManager;
|
fvkmemory::ResourceManager mResourceManager;
|
||||||
@@ -146,39 +143,21 @@ private:
|
|||||||
VulkanDescriptorSetLayoutCache mDescriptorSetLayoutCache;
|
VulkanDescriptorSetLayoutCache mDescriptorSetLayoutCache;
|
||||||
VulkanDescriptorSetCache mDescriptorSetCache;
|
VulkanDescriptorSetCache mDescriptorSetCache;
|
||||||
VulkanQueryManager mQueryManager;
|
VulkanQueryManager mQueryManager;
|
||||||
VulkanExternalImageManager mExternalImageManager;
|
|
||||||
|
|
||||||
// This is necessary for us to write to push constants after binding a pipeline.
|
// This is necessary for us to write to push constants after binding a pipeline.
|
||||||
using DescriptorSetLayoutHandleList = std::array<resource_ptr<VulkanDescriptorSetLayout>,
|
|
||||||
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
|
|
||||||
|
|
||||||
struct BindInDrawBundle {
|
|
||||||
PipelineState pipelineState = {};
|
|
||||||
DescriptorSetLayoutHandleList dsLayoutHandles = {};
|
|
||||||
fvkutils::DescriptorSetMask descriptorSetMask = {};
|
|
||||||
resource_ptr<VulkanProgram> program = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
// For push constant
|
resource_ptr<VulkanProgram> program;
|
||||||
resource_ptr<VulkanProgram> program = {};
|
VkPipelineLayout pipelineLayout;
|
||||||
// For push commiting dynamic ubos in draw()
|
fvkutils::DescriptorSetMask descriptorSetMask;
|
||||||
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
} mBoundPipeline = {};
|
||||||
fvkutils::DescriptorSetMask descriptorSetMask = {};
|
|
||||||
|
|
||||||
std::pair<bool, BindInDrawBundle> bindInDraw = {false, {}};
|
|
||||||
} mPipelineState = {};
|
|
||||||
|
|
||||||
|
// We need to store information about a render pass to enable better barriers at the end of a
|
||||||
|
// renderpass.
|
||||||
struct {
|
struct {
|
||||||
// This tracks whether the app has seen external samplers bound to a the descriptor set.
|
using AttachmentArray =
|
||||||
// This will force bindPipeline to take a slow path.
|
fvkutils::StaticVector<VulkanAttachment, MAX_RENDERTARGET_ATTACHMENT_TEXTURES>;
|
||||||
bool hasExternalSamplerLayouts = false;
|
AttachmentArray attachments;
|
||||||
bool hasBoundExternalImages = false;
|
} mRenderPassFboInfo = {};
|
||||||
|
|
||||||
bool hasExternalSamplers() const noexcept {
|
|
||||||
return hasExternalSamplerLayouts && hasBoundExternalImages;
|
|
||||||
}
|
|
||||||
} mAppState;
|
|
||||||
|
|
||||||
bool const mIsSRGBSwapChainSupported;
|
bool const mIsSRGBSwapChainSupported;
|
||||||
backend::StereoscopicType const mStereoscopicType;
|
backend::StereoscopicType const mStereoscopicType;
|
||||||
|
|||||||
@@ -1,294 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* 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 "VulkanExternalImageManager.h"
|
|
||||||
|
|
||||||
#include "VulkanDescriptorSetCache.h"
|
|
||||||
#include "VulkanDescriptorSetLayoutCache.h"
|
|
||||||
#include "VulkanSamplerCache.h"
|
|
||||||
#include "VulkanYcbcrConversionCache.h"
|
|
||||||
#include "vulkan/memory/ResourcePointer.h"
|
|
||||||
#include "vulkan/utils/Conversion.h"
|
|
||||||
|
|
||||||
#include <backend/platforms/VulkanPlatform.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using Bitmask = fvkutils::UniformBufferBitmask;
|
|
||||||
static_assert(sizeof(Bitmask) * 8 == fvkutils::MAX_DESCRIPTOR_SET_BITMASK_BITS);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void erasep(std::vector<T>& v, std::function<bool(T const&)> f) {
|
|
||||||
auto newEnd = std::remove_if(v.begin(), v.end(), f);
|
|
||||||
v.erase(newEnd, v.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
using ImageData = VulkanExternalImageManager::VulkanExternalImageManager::ImageData;
|
|
||||||
ImageData& findImage(std::vector<ImageData>& images,
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> texture) {
|
|
||||||
auto itr = std::find_if(images.begin(), images.end(), [&](ImageData const& data) {
|
|
||||||
return data.image == texture;
|
|
||||||
});
|
|
||||||
assert_invariant(itr != images.end());
|
|
||||||
return *itr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void copySet(VkDevice device, VkDescriptorSet srcSet, VkDescriptorSet dstSet, Bitmask bindings) {
|
|
||||||
// TODO: fix the size for better memory management
|
|
||||||
std::vector<VkCopyDescriptorSet> copies;
|
|
||||||
bindings.forEachSetBit([&](size_t index) {
|
|
||||||
copies.push_back({
|
|
||||||
.sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET,
|
|
||||||
.srcSet = srcSet,
|
|
||||||
.srcBinding = (uint32_t) index,
|
|
||||||
.dstSet = dstSet,
|
|
||||||
.dstBinding = (uint32_t) index,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
vkUpdateDescriptorSets(device, 0, nullptr, copies.size(), copies.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmask foldBitsInHalf(Bitmask bitset) {
|
|
||||||
Bitmask outBitset;
|
|
||||||
bitset.forEachSetBit([&](size_t index) {
|
|
||||||
constexpr size_t BITMASK_LOWER_BITS_LEN = sizeof(outBitset) * 4;
|
|
||||||
outBitset.set(index % BITMASK_LOWER_BITS_LEN);
|
|
||||||
});
|
|
||||||
return outBitset;
|
|
||||||
}
|
|
||||||
|
|
||||||
}// namespace
|
|
||||||
|
|
||||||
VulkanExternalImageManager::VulkanExternalImageManager(VulkanPlatform* platform,
|
|
||||||
VulkanSamplerCache* samplerCache, VulkanYcbcrConversionCache* ycbcrConversionCache,
|
|
||||||
VulkanDescriptorSetCache* setCache, VulkanDescriptorSetLayoutCache* layoutCache)
|
|
||||||
: mPlatform(platform),
|
|
||||||
mSamplerCache(samplerCache),
|
|
||||||
mYcbcrConversionCache(ycbcrConversionCache),
|
|
||||||
mDescriptorSetCache(setCache),
|
|
||||||
mDescriptorSetLayoutCache(layoutCache) {
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanExternalImageManager::~VulkanExternalImageManager() = default;
|
|
||||||
|
|
||||||
void VulkanExternalImageManager::terminate() {
|
|
||||||
mSetBindings.clear();
|
|
||||||
mImages.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanExternalImageManager::onBeginFrame() {
|
|
||||||
std::for_each(mImages.begin(), mImages.end(), [](ImageData& image) {
|
|
||||||
image.hasBeenValidated = false;
|
|
||||||
});
|
|
||||||
std::for_each(mSetBindings.begin(), mSetBindings.end(), [](SetBindingInfo& info) {
|
|
||||||
info.bound = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fvkutils::DescriptorSetMask VulkanExternalImageManager::prepareBindSets(LayoutArray const& layouts,
|
|
||||||
SetArray const& sets) {
|
|
||||||
fvkutils::DescriptorSetMask shouldUseExternalSampler{};
|
|
||||||
for (uint8_t i = 0; i < sets.size(); i++) {
|
|
||||||
auto set = sets[i];
|
|
||||||
auto layout = layouts[i];
|
|
||||||
if (!set || !layout) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (hasExternalSampler(set)) {
|
|
||||||
updateSetAndLayout(set, layout);
|
|
||||||
shouldUseExternalSampler.set(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return shouldUseExternalSampler;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VulkanExternalImageManager::hasExternalSampler(
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set) {
|
|
||||||
auto itr = std::find_if(mSetBindings.begin(), mSetBindings.end(),
|
|
||||||
[&](SetBindingInfo const& info) { return info.set == set; });
|
|
||||||
return itr != mSetBindings.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanExternalImageManager::updateSetAndLayout(
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
|
||||||
utils::FixedCapacityVector<
|
|
||||||
std::tuple<uint8_t, VkSampler, fvkmemory::resource_ptr<VulkanTexture>>>
|
|
||||||
samplerAndBindings;
|
|
||||||
samplerAndBindings.reserve(MAX_SAMPLER_COUNT);
|
|
||||||
|
|
||||||
fvkutils::SamplerBitmask actualExternalSamplers;
|
|
||||||
for (auto& bindingInfo : mSetBindings) {
|
|
||||||
if (bindingInfo.set != set || bindingInfo.bound) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto& imageData = findImage(mImages, bindingInfo.image);
|
|
||||||
updateImage(&imageData);
|
|
||||||
|
|
||||||
auto samplerParams = bindingInfo.samplerParams;
|
|
||||||
// according to spec, these must match chromaFilter
|
|
||||||
// https://registry.khronos.org/vulkan/specs/latest/man/html/VkSamplerCreateInfo.html#VUID-VkSamplerCreateInfo-minFilter-01645
|
|
||||||
samplerParams.filterMag = SamplerMagFilter::NEAREST;
|
|
||||||
samplerParams.filterMin = SamplerMinFilter::NEAREST;
|
|
||||||
|
|
||||||
auto sampler = mSamplerCache->getSampler({
|
|
||||||
.sampler = samplerParams,
|
|
||||||
.conversion = imageData.conversion,
|
|
||||||
});
|
|
||||||
actualExternalSamplers.set(bindingInfo.binding);
|
|
||||||
samplerAndBindings.push_back({ bindingInfo.binding, sampler, bindingInfo.image });
|
|
||||||
bindingInfo.bound = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (samplerAndBindings.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort by binding number
|
|
||||||
std::sort(samplerAndBindings.begin(), samplerAndBindings.end(), [](auto const& a, auto const& b) {
|
|
||||||
return std::get<0>(a) < std::get<0>(b);
|
|
||||||
});
|
|
||||||
|
|
||||||
utils::FixedCapacityVector<VkSampler> outSamplers;
|
|
||||||
outSamplers.reserve(MAX_SAMPLER_COUNT);
|
|
||||||
std::for_each(samplerAndBindings.begin(), samplerAndBindings.end(),
|
|
||||||
[&](auto const& b) { outSamplers.push_back(std::get<1>(b)); });
|
|
||||||
|
|
||||||
VkDescriptorSetLayout const oldLayout = layout->getExternalSamplerVkLayout();
|
|
||||||
VkDescriptorSetLayout const newLayout = mDescriptorSetLayoutCache->getVkLayout(layout->bitmask,
|
|
||||||
actualExternalSamplers, outSamplers);
|
|
||||||
|
|
||||||
// Need to copy the set
|
|
||||||
VkDescriptorSet const oldSet = set->getExternalSamplerVkSet();
|
|
||||||
if (oldLayout != newLayout || oldSet == VK_NULL_HANDLE) {
|
|
||||||
// Build a new descriptor set from the new layout
|
|
||||||
VkDescriptorSet const newSet = mDescriptorSetCache->getVkSet(layout->count, newLayout);
|
|
||||||
auto const ubo = layout->bitmask.ubo | layout->bitmask.dynamicUbo;
|
|
||||||
auto const samplers = layout->bitmask.sampler & (~actualExternalSamplers);
|
|
||||||
|
|
||||||
// Each bitmask denotes a binding index, and separated into two stages - vertex and buffer
|
|
||||||
// We fold the two stages into just the lower half of the bits to denote a combined set of
|
|
||||||
// bindings.
|
|
||||||
Bitmask const copyBindings = foldBitsInHalf(ubo | samplers);
|
|
||||||
VkDescriptorSet const srcSet = oldSet != VK_NULL_HANDLE ? oldSet : set->getVkSet();
|
|
||||||
copySet(mPlatform->getDevice(), srcSet, newSet, copyBindings);
|
|
||||||
|
|
||||||
set->setExternalSamplerVkSet(newSet, [&](VulkanDescriptorSet*) {
|
|
||||||
mDescriptorSetCache->manualRecycle(layout->count, newLayout, newSet);
|
|
||||||
});
|
|
||||||
if (oldLayout != newLayout) {
|
|
||||||
layout->setExternalSamplerVkLayout(newLayout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the external samplers in the set
|
|
||||||
for (auto& [binding, sampler, image]: samplerAndBindings) {
|
|
||||||
mDescriptorSetCache->updateSamplerForExternalSamplerSet(set, binding, image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerYcbcrConversion VulkanExternalImageManager::getVkSamplerYcbcrConversion(
|
|
||||||
VulkanPlatform::ExternalImageMetadata const& metadata) {
|
|
||||||
// This external image does not require external sampler (YUV conversion).
|
|
||||||
if (metadata.externalFormat == 0 && !fvkutils::isVKYcbcrConversionFormat(metadata.format)) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
VulkanYcbcrConversionCache::Params ycbcrParams = {
|
|
||||||
.conversion = {
|
|
||||||
.ycbcrModel = fvkutils::getYcbcrModelConversionFilament(metadata.ycbcrModel),
|
|
||||||
.r = fvkutils::getSwizzleFilament(metadata.ycbcrConversionComponents.r, 0),
|
|
||||||
.g = fvkutils::getSwizzleFilament(metadata.ycbcrConversionComponents.g, 1),
|
|
||||||
.b = fvkutils::getSwizzleFilament(metadata.ycbcrConversionComponents.b, 2),
|
|
||||||
.a = fvkutils::getSwizzleFilament(metadata.ycbcrConversionComponents.a, 3),
|
|
||||||
.ycbcrRange = fvkutils::getYcbcrRangeFilament(metadata.ycbcrRange),
|
|
||||||
.xChromaOffset = fvkutils::getChromaLocationFilament(metadata.xChromaOffset),
|
|
||||||
.yChromaOffset = fvkutils::getChromaLocationFilament(metadata.yChromaOffset),
|
|
||||||
|
|
||||||
// Unclear where to get the chromaFilter, we just assume it's nearest.
|
|
||||||
.chromaFilter = SamplerMagFilter::NEAREST,
|
|
||||||
},
|
|
||||||
.format = metadata.format,
|
|
||||||
.externalFormat = metadata.externalFormat,
|
|
||||||
};
|
|
||||||
return mYcbcrConversionCache->getConversion(ycbcrParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanExternalImageManager::updateImage(ImageData* image) {
|
|
||||||
if (image->hasBeenValidated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
image->hasBeenValidated = true;
|
|
||||||
|
|
||||||
auto metadata = mPlatform->extractExternalImageMetadata(image->platformHandle);
|
|
||||||
auto vkYcbcr = getVkSamplerYcbcrConversion(metadata);
|
|
||||||
if (vkYcbcr == image->conversion) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
image->image->setYcbcrConversion(vkYcbcr);
|
|
||||||
image->conversion = vkYcbcr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanExternalImageManager::removeDescriptorSet(
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> inSet) {
|
|
||||||
erasep<SetBindingInfo>(mSetBindings,
|
|
||||||
[&](auto const& bindingInfo) { return (bindingInfo.set == inSet); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanExternalImageManager::bindExternallySampledTexture(
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t bindingPoint,
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> image, SamplerParams samplerParams) {
|
|
||||||
// Should we do duplicate validation here?
|
|
||||||
auto& imageData = findImage(mImages, image);
|
|
||||||
mSetBindings.push_back({ bindingPoint, imageData.image, set, samplerParams });
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanExternalImageManager::addExternallySampledTexture(
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> image,
|
|
||||||
Platform::ExternalImageHandleRef platformHandleRef) {
|
|
||||||
mImages.push_back({ image, platformHandleRef, false });
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanExternalImageManager::removeExternallySampledTexture(
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> image) {
|
|
||||||
erasep<SetBindingInfo>(mSetBindings,
|
|
||||||
[&](auto const& bindingInfo) { return (bindingInfo.image == image); });
|
|
||||||
erasep<ImageData>(mImages, [&](auto const& imageData) {
|
|
||||||
return imageData.image == image;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VulkanExternalImageManager::isExternallySampledTexture(
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> image) const {
|
|
||||||
return std::find_if(mImages.begin(), mImages.end(), [&](auto const& imageData) {
|
|
||||||
return imageData.image == image;
|
|
||||||
}) != mImages.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanExternalImageManager::clearTextureBinding(
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t bindingPoint) {
|
|
||||||
erasep<SetBindingInfo>(mSetBindings, [&](auto const& bindingInfo) {
|
|
||||||
return (bindingInfo.set == set && bindingInfo.binding == bindingPoint);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namesapce filament::backend
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANEXTERNALIMAGEMANAGER_H
|
|
||||||
#define TNT_FILAMENT_BACKEND_CACHING_VULKANEXTERNALIMAGEMANAGER_H
|
|
||||||
|
|
||||||
#include "VulkanHandles.h"
|
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
class VulkanYcbcrConversionCache;
|
|
||||||
class VulkanSamplerCache;
|
|
||||||
class VulkanDescriptorSetLayoutCache;
|
|
||||||
class VulkanDescriptorSetCache;
|
|
||||||
|
|
||||||
// Manages the logic of external images and their quirks wrt Vulikan.
|
|
||||||
class VulkanExternalImageManager {
|
|
||||||
public:
|
|
||||||
|
|
||||||
VulkanExternalImageManager(
|
|
||||||
VulkanPlatform* platform,
|
|
||||||
VulkanSamplerCache* samplerCache,
|
|
||||||
VulkanYcbcrConversionCache* ycbcrConversionCache,
|
|
||||||
VulkanDescriptorSetCache* setCache,
|
|
||||||
VulkanDescriptorSetLayoutCache* layoutCache);
|
|
||||||
|
|
||||||
~VulkanExternalImageManager();
|
|
||||||
|
|
||||||
void terminate();
|
|
||||||
|
|
||||||
void onBeginFrame();
|
|
||||||
|
|
||||||
using SetArray = std::array<fvkmemory::resource_ptr<VulkanDescriptorSet>,
|
|
||||||
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
|
|
||||||
|
|
||||||
using LayoutArray = std::array<fvkmemory::resource_ptr<VulkanDescriptorSetLayout>,
|
|
||||||
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
|
|
||||||
|
|
||||||
using VkLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
|
|
||||||
|
|
||||||
// Returns bitmask to indicate whether or not to use the external sampler version of each
|
|
||||||
// descriptor set.
|
|
||||||
fvkutils::DescriptorSetMask prepareBindSets(LayoutArray const& layouts, SetArray const& sets);
|
|
||||||
|
|
||||||
void removeDescriptorSet(fvkmemory::resource_ptr<VulkanDescriptorSet> set);
|
|
||||||
|
|
||||||
void bindExternallySampledTexture(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
|
||||||
uint8_t bindingPoint, fvkmemory::resource_ptr<VulkanTexture> image,
|
|
||||||
SamplerParams samplerParams);
|
|
||||||
|
|
||||||
void clearTextureBinding(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
|
||||||
uint8_t bindingPoint);
|
|
||||||
|
|
||||||
void addExternallySampledTexture(fvkmemory::resource_ptr<VulkanTexture> external,
|
|
||||||
Platform::ExternalImageHandleRef platformHandleRef);
|
|
||||||
|
|
||||||
void removeExternallySampledTexture(fvkmemory::resource_ptr<VulkanTexture> image);
|
|
||||||
|
|
||||||
bool isExternallySampledTexture(fvkmemory::resource_ptr<VulkanTexture> image) const;
|
|
||||||
|
|
||||||
VkSamplerYcbcrConversion getVkSamplerYcbcrConversion(
|
|
||||||
VulkanPlatform::ExternalImageMetadata const& metadata);
|
|
||||||
|
|
||||||
struct ImageData {
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> image;
|
|
||||||
Platform::ExternalImageHandle platformHandle;
|
|
||||||
bool hasBeenValidated = false; // indicates whether the image has been validated *this frame*
|
|
||||||
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool hasExternalSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set);
|
|
||||||
|
|
||||||
void updateSetAndLayout(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
|
|
||||||
|
|
||||||
void updateImage(ImageData* imageData);
|
|
||||||
|
|
||||||
VulkanPlatform* mPlatform;
|
|
||||||
VulkanSamplerCache* mSamplerCache;
|
|
||||||
VulkanYcbcrConversionCache* mYcbcrConversionCache;
|
|
||||||
VulkanDescriptorSetCache* mDescriptorSetCache;
|
|
||||||
VulkanDescriptorSetLayoutCache* mDescriptorSetLayoutCache;
|
|
||||||
|
|
||||||
using SetAndLayout = std::pair<fvkmemory::resource_ptr<VulkanDescriptorSet>,
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>>;
|
|
||||||
|
|
||||||
struct SetBindingInfo {
|
|
||||||
uint8_t binding = 0;
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> image;
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set;
|
|
||||||
SamplerParams samplerParams;
|
|
||||||
bool bound = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Use vectors instead of hash maps because we only expect small number of entries.
|
|
||||||
std::vector<SetBindingInfo> mSetBindings;
|
|
||||||
std::vector<ImageData> mImages;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // filament::backend
|
|
||||||
|
|
||||||
#endif // TNT_FILAMENT_BACKEND_CACHING_VULKANEXTERNALIMAGEMANAGER_H
|
|
||||||
@@ -330,20 +330,12 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept
|
|||||||
mRenderPassCache[config] = {renderPass, mCurrentTime};
|
mRenderPassCache[config] = {renderPass, mCurrentTime};
|
||||||
|
|
||||||
#if FVK_ENABLED(FVK_DEBUG_FBO_CACHE)
|
#if FVK_ENABLED(FVK_DEBUG_FBO_CACHE)
|
||||||
FVK_LOGD << "Created render pass " << renderPass << " with ";
|
FVK_LOGD << "Created render pass " << renderPass << " with "
|
||||||
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; ++i) {
|
<< "samples = " << int(config.samples) << ", "
|
||||||
FVK_LOGD << (int) config.colorFormat[i] << " ";
|
<< "depth = " << (hasDepth ? 1 : 0) << ", "
|
||||||
}
|
<< "colorAttachmentCount[0] = " << subpasses[0].colorAttachmentCount
|
||||||
FVK_LOGD << ", "
|
<< utils::io::endl;
|
||||||
<< "depth = " << config.depthFormat << ", "
|
#endif
|
||||||
<< "initialDepthLayout = " << (int) config.initialDepthLayout << ", "
|
|
||||||
<< "samples = " << int(config.samples) << ", "
|
|
||||||
<< "needsResolveMask = " << int(config.needsResolveMask) << ", "
|
|
||||||
<< "usesLazilyAllocatedMemory = " << int(config.usesLazilyAllocatedMemory) << ", "
|
|
||||||
<< "viewCount = " << int(config.viewCount) << ", "
|
|
||||||
<< "colorAttachmentCount[0] = " << subpasses[0].colorAttachmentCount
|
|
||||||
<< utils::io::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return renderPass;
|
return renderPass;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,18 +149,11 @@ void VulkanDescriptorSet::acquire(fvkmemory::resource_ptr<VulkanBufferObject> ob
|
|||||||
mResources.push_back(obj);
|
mResources.push_back(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(DescriptorSetLayout&& layout,
|
VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(DescriptorSetLayout const& layout)
|
||||||
VkDescriptorSetLayout vkLayout)
|
|
||||||
: bitmask(fromBackendLayout(layout)),
|
: bitmask(fromBackendLayout(layout)),
|
||||||
count(Count::fromLayoutBitmask(bitmask)),
|
count(Count::fromLayoutBitmask(bitmask)) {}
|
||||||
mVkLayout(vkLayout) {}
|
|
||||||
|
|
||||||
VulkanDescriptorSetLayout::Bitmask VulkanDescriptorSetLayout::Bitmask::fromLayoutDescription(
|
PushConstantDescription::PushConstantDescription(backend::Program const& program) noexcept {
|
||||||
DescriptorSetLayout const& layout) {
|
|
||||||
return fromBackendLayout(layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
PushConstantDescription::PushConstantDescription(backend::Program const& program) {
|
|
||||||
mRangeCount = 0;
|
mRangeCount = 0;
|
||||||
for (auto stage : { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) {
|
for (auto stage : { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) {
|
||||||
auto const& constants = program.getPushConstants(stage);
|
auto const& constants = program.getPushConstants(stage);
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso
|
|||||||
fvkutils::SamplerBitmask sampler; // 8 bytes
|
fvkutils::SamplerBitmask sampler; // 8 bytes
|
||||||
fvkutils::InputAttachmentBitmask inputAttachment; // 8 bytes
|
fvkutils::InputAttachmentBitmask inputAttachment; // 8 bytes
|
||||||
|
|
||||||
// This is a subset of the sampler field.
|
// This is a subset of the bitmask.sampler field.
|
||||||
fvkutils::SamplerBitmask externalSampler; // 8 bytes
|
fvkutils::SamplerBitmask externalSampler; // 8 bytes
|
||||||
|
|
||||||
bool operator==(Bitmask const& right) const {
|
bool operator==(Bitmask const& right) const {
|
||||||
@@ -79,8 +79,6 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso
|
|||||||
inputAttachment == right.inputAttachment &&
|
inputAttachment == right.inputAttachment &&
|
||||||
externalSampler == right.externalSampler;
|
externalSampler == right.externalSampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bitmask fromLayoutDescription(DescriptorSetLayout const& layout);
|
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Bitmask) == 40);
|
static_assert(sizeof(Bitmask) == 40);
|
||||||
|
|
||||||
@@ -122,20 +120,16 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
VulkanDescriptorSetLayout(DescriptorSetLayout&& layout, VkDescriptorSetLayout vkLayout);
|
VulkanDescriptorSetLayout(DescriptorSetLayout const& layout);
|
||||||
|
|
||||||
// Note that we don't destroy the vklayout. This is done by the layout cache.
|
// Note that we don't destroy the vklayout. This is done by the layout cache.
|
||||||
~VulkanDescriptorSetLayout() = default;
|
~VulkanDescriptorSetLayout() = default;
|
||||||
|
|
||||||
VkDescriptorSetLayout getVkLayout() const noexcept { return mVkLayout; }
|
VkDescriptorSetLayout const& getVkLayout() const noexcept { return mVkLayout; }
|
||||||
|
|
||||||
VkDescriptorSetLayout getExternalSamplerVkLayout() const noexcept {
|
// It is possible to have the layout switch out due to AHardwarebuffer (external image) format
|
||||||
return mExternalSamplerVkLayout;
|
// changes.
|
||||||
}
|
void setVkLayout(VkDescriptorSetLayout vklayout) noexcept { mVkLayout = vklayout; }
|
||||||
|
|
||||||
void setExternalSamplerVkLayout(VkDescriptorSetLayout vklayout) noexcept {
|
|
||||||
mExternalSamplerVkLayout = vklayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasExternalSamplers() const noexcept { return bitmask.externalSampler.count() > 0; }
|
bool hasExternalSamplers() const noexcept { return bitmask.externalSampler.count() > 0; }
|
||||||
|
|
||||||
@@ -143,11 +137,7 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso
|
|||||||
Count const count;
|
Count const count;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// This is the layout without any immutable samplers.
|
VkDescriptorSetLayout mVkLayout = VK_NULL_HANDLE;
|
||||||
VkDescriptorSetLayout const mVkLayout = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
// This is the layout with immutable samplers, and can be updated.
|
|
||||||
VkDescriptorSetLayout mExternalSamplerVkLayout = VK_NULL_HANDLE;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VulkanDescriptorSet : public HwDescriptorSet, fvkmemory::Resource {
|
struct VulkanDescriptorSet : public HwDescriptorSet, fvkmemory::Resource {
|
||||||
@@ -159,37 +149,23 @@ public:
|
|||||||
VulkanDescriptorSet(
|
VulkanDescriptorSet(
|
||||||
fvkutils::UniformBufferBitmask const& dynamicUboMask,
|
fvkutils::UniformBufferBitmask const& dynamicUboMask,
|
||||||
uint8_t uniqueDynamicUboCount,
|
uint8_t uniqueDynamicUboCount,
|
||||||
OnRecycle&& onRecycleFn, VkDescriptorSet vkSet)
|
OnRecycle&& onRecycleFn)
|
||||||
: dynamicUboMask(dynamicUboMask),
|
: dynamicUboMask(dynamicUboMask),
|
||||||
uniqueDynamicUboCount(uniqueDynamicUboCount),
|
uniqueDynamicUboCount(uniqueDynamicUboCount),
|
||||||
mVkSet(vkSet),
|
|
||||||
mOnRecycleFn(std::move(onRecycleFn)) {}
|
mOnRecycleFn(std::move(onRecycleFn)) {}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(bugprone-exception-escape)
|
|
||||||
~VulkanDescriptorSet() {
|
~VulkanDescriptorSet() {
|
||||||
if (mOnRecycleFn) {
|
if (mOnRecycleFn) {
|
||||||
mOnRecycleFn(this);
|
mOnRecycleFn(this);
|
||||||
}
|
}
|
||||||
if (mOnRecycleExternalSamplerFn) {
|
|
||||||
mOnRecycleExternalSamplerFn(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSet getVkSet() const noexcept {
|
VkDescriptorSet const& getVkSet() const noexcept {
|
||||||
return mVkSet;
|
return mVkSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSet getExternalSamplerVkSet() const noexcept {
|
// Note that the only case where you'd set it more than once is with external images/samplers.
|
||||||
return mExternalSamplerVkSet;
|
void setVkSet(VkDescriptorSet vkset) noexcept { mVkSet = vkset; }
|
||||||
}
|
|
||||||
|
|
||||||
void setExternalSamplerVkSet(VkDescriptorSet vkset, OnRecycle onRecycle) {
|
|
||||||
mExternalSamplerVkSet = vkset;
|
|
||||||
if (mOnRecycleExternalSamplerFn) {
|
|
||||||
mOnRecycleExternalSamplerFn(this);
|
|
||||||
}
|
|
||||||
mOnRecycleExternalSamplerFn = onRecycle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOffsets(backend::DescriptorSetOffsetArray&& offsets) noexcept {
|
void setOffsets(backend::DescriptorSetOffsetArray&& offsets) noexcept {
|
||||||
mOffsets = std::move(offsets);
|
mOffsets = std::move(offsets);
|
||||||
@@ -206,20 +182,17 @@ public:
|
|||||||
uint8_t const uniqueDynamicUboCount;
|
uint8_t const uniqueDynamicUboCount;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkDescriptorSet const mVkSet;
|
VkDescriptorSet mVkSet = VK_NULL_HANDLE;
|
||||||
VkDescriptorSet mExternalSamplerVkSet = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
backend::DescriptorSetOffsetArray mOffsets;
|
backend::DescriptorSetOffsetArray mOffsets;
|
||||||
std::vector<fvkmemory::resource_ptr<fvkmemory::Resource>> mResources;
|
std::vector<fvkmemory::resource_ptr<fvkmemory::Resource>> mResources;
|
||||||
OnRecycle mOnRecycleFn;
|
OnRecycle mOnRecycleFn;
|
||||||
OnRecycle mOnRecycleExternalSamplerFn;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using PushConstantNameArray = utils::FixedCapacityVector<char const*>;
|
using PushConstantNameArray = utils::FixedCapacityVector<char const*>;
|
||||||
using PushConstantNameByStage = std::array<PushConstantNameArray, Program::SHADER_TYPE_COUNT>;
|
using PushConstantNameByStage = std::array<PushConstantNameArray, Program::SHADER_TYPE_COUNT>;
|
||||||
|
|
||||||
struct PushConstantDescription {
|
struct PushConstantDescription {
|
||||||
explicit PushConstantDescription(backend::Program const& program);
|
explicit PushConstantDescription(backend::Program const& program) noexcept;
|
||||||
|
|
||||||
VkPushConstantRange const* getVkRanges() const noexcept { return mRanges; }
|
VkPushConstantRange const* getVkRanges() const noexcept { return mRanges; }
|
||||||
uint32_t getVkRangeCount() const noexcept { return mRangeCount; }
|
uint32_t getVkRangeCount() const noexcept { return mRangeCount; }
|
||||||
|
|||||||
@@ -66,12 +66,8 @@ void VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) {
|
|||||||
// If an error occurred, allow higher levels to handle it gracefully.
|
// If an error occurred, allow higher levels to handle it gracefully.
|
||||||
assert_invariant(cacheEntry != nullptr && "Failed to create/find pipeline");
|
assert_invariant(cacheEntry != nullptr && "Failed to create/find pipeline");
|
||||||
|
|
||||||
|
mBoundPipeline = mPipelineRequirements;
|
||||||
static PipelineEqual equal;
|
vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, cacheEntry->handle);
|
||||||
if (!equal(mBoundPipeline, mPipelineRequirements)) {
|
|
||||||
mBoundPipeline = mPipelineRequirements;
|
|
||||||
vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, cacheEntry->handle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() noexcept {
|
VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() noexcept {
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
|
|||||||
mTaskHandler->post(std::move(waitFenceFunc), std::move(cleanPbdFunc));
|
mTaskHandler->post(std::move(waitFenceFunc), std::move(cleanPbdFunc));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanReadPixels::runUntilComplete() {
|
void VulkanReadPixels::runUntilComplete() noexcept {
|
||||||
if (!mTaskHandler) {
|
if (!mTaskHandler) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public:
|
|||||||
OnReadCompleteFunction const& readCompleteFunc);
|
OnReadCompleteFunction const& readCompleteFunc);
|
||||||
|
|
||||||
// This method will block until all of the in-flight requests are complete.
|
// This method will block until all of the in-flight requests are complete.
|
||||||
void runUntilComplete();
|
void runUntilComplete() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkDevice mDevice = VK_NULL_HANDLE;
|
VkDevice mDevice = VK_NULL_HANDLE;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace filament::backend {
|
|||||||
VulkanSamplerCache::VulkanSamplerCache(VkDevice device)
|
VulkanSamplerCache::VulkanSamplerCache(VkDevice device)
|
||||||
: mDevice(device) {}
|
: mDevice(device) {}
|
||||||
|
|
||||||
VkSampler VulkanSamplerCache::getSampler(Params params) {
|
VkSampler VulkanSamplerCache::getSampler(Params params) noexcept {
|
||||||
auto iter = mCache.find(params);
|
auto iter = mCache.find(params);
|
||||||
if (UTILS_LIKELY(iter != mCache.end())) {
|
if (UTILS_LIKELY(iter != mCache.end())) {
|
||||||
return iter->second;
|
return iter->second;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
static_assert(sizeof(Params) == 16);
|
static_assert(sizeof(Params) == 16);
|
||||||
|
|
||||||
explicit VulkanSamplerCache(VkDevice device);
|
explicit VulkanSamplerCache(VkDevice device);
|
||||||
VkSampler getSampler(Params params);
|
VkSampler getSampler(Params params) noexcept;
|
||||||
void terminate() noexcept;
|
void terminate() noexcept;
|
||||||
private:
|
private:
|
||||||
VkDevice mDevice;
|
VkDevice mDevice;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
static constexpr uint32_t TIME_BEFORE_EVICTION = 3;
|
static constexpr uint32_t TIME_BEFORE_EVICTION = FVK_MAX_COMMAND_BUFFERS;
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) {
|
|||||||
auto stage = iter->second;
|
auto stage = iter->second;
|
||||||
mFreeStages.erase(iter);
|
mFreeStages.erase(iter);
|
||||||
stage->lastAccessed = mCurrentFrame;
|
stage->lastAccessed = mCurrentFrame;
|
||||||
mUsedStages.push_back(stage);
|
mUsedStages.insert(stage);
|
||||||
return stage;
|
return stage;
|
||||||
}
|
}
|
||||||
// We were not able to find a sufficiently large stage, so create a new one.
|
// We were not able to find a sufficiently large stage, so create a new one.
|
||||||
@@ -51,7 +51,7 @@ VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Create the VkBuffer.
|
// Create the VkBuffer.
|
||||||
mUsedStages.push_back(stage);
|
mUsedStages.insert(stage);
|
||||||
VkBufferCreateInfo bufferInfo {
|
VkBufferCreateInfo bufferInfo {
|
||||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||||
.size = numBytes,
|
.size = numBytes,
|
||||||
@@ -77,7 +77,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi
|
|||||||
if (image->format == vkformat && image->width == width && image->height == height) {
|
if (image->format == vkformat && image->width == width && image->height == height) {
|
||||||
mFreeImages.erase(image);
|
mFreeImages.erase(image);
|
||||||
image->lastAccessed = mCurrentFrame;
|
image->lastAccessed = mCurrentFrame;
|
||||||
mUsedImages.push_back(image);
|
mUsedImages.insert(image);
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi
|
|||||||
.lastAccessed = mCurrentFrame,
|
.lastAccessed = mCurrentFrame,
|
||||||
});
|
});
|
||||||
|
|
||||||
mUsedImages.push_back(image);
|
mUsedImages.insert(image);
|
||||||
|
|
||||||
const VkImageCreateInfo imageInfo = {
|
const VkImageCreateInfo imageInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||||
@@ -161,7 +161,7 @@ void VulkanStagePool::gc() noexcept {
|
|||||||
stage->lastAccessed = mCurrentFrame;
|
stage->lastAccessed = mCurrentFrame;
|
||||||
mFreeStages.insert(std::make_pair(stage->capacity, stage));
|
mFreeStages.insert(std::make_pair(stage->capacity, stage));
|
||||||
} else {
|
} else {
|
||||||
mUsedStages.push_back(stage);
|
mUsedStages.insert(stage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@ void VulkanStagePool::gc() noexcept {
|
|||||||
image->lastAccessed = mCurrentFrame;
|
image->lastAccessed = mCurrentFrame;
|
||||||
mFreeImages.insert(image);
|
mFreeImages.insert(image);
|
||||||
} else {
|
} else {
|
||||||
mUsedImages.push_back(image);
|
mUsedImages.insert(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FVK_SYSTRACE_END();
|
FVK_SYSTRACE_END();
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -74,10 +73,10 @@ private:
|
|||||||
std::multimap<uint32_t, VulkanStage const*> mFreeStages;
|
std::multimap<uint32_t, VulkanStage const*> mFreeStages;
|
||||||
|
|
||||||
// Simple unordered set for stashing a list of in-use stages that can be reclaimed later.
|
// Simple unordered set for stashing a list of in-use stages that can be reclaimed later.
|
||||||
std::vector<VulkanStage const*> mUsedStages;
|
std::unordered_set<VulkanStage const*> mUsedStages;
|
||||||
|
|
||||||
std::unordered_set<VulkanStageImage const*> mFreeImages;
|
std::unordered_set<VulkanStageImage const*> mFreeImages;
|
||||||
std::vector<VulkanStageImage const*> mUsedImages;
|
std::unordered_set<VulkanStageImage const*> mUsedImages;
|
||||||
|
|
||||||
// Store the current "time" (really just a frame count) and LRU eviction parameters.
|
// Store the current "time" (really just a frame count) and LRU eviction parameters.
|
||||||
uint64_t mCurrentFrame = 0;
|
uint64_t mCurrentFrame = 0;
|
||||||
|
|||||||
@@ -223,7 +223,8 @@ VkImageUsageFlags getUsage(VulkanContext const& context, uint8_t samples,
|
|||||||
VulkanTextureState::VulkanTextureState(VulkanStagePool& stagePool, VulkanCommands* commands,
|
VulkanTextureState::VulkanTextureState(VulkanStagePool& stagePool, VulkanCommands* commands,
|
||||||
VmaAllocator allocator, VkDevice device, VkImage image, VkDeviceMemory deviceMemory,
|
VmaAllocator allocator, VkDevice device, VkImage image, VkDeviceMemory deviceMemory,
|
||||||
VkFormat format, VkImageViewType viewType, uint8_t levels, uint8_t layerCount,
|
VkFormat format, VkImageViewType viewType, uint8_t levels, uint8_t layerCount,
|
||||||
VkSamplerYcbcrConversion ycbcrConversion, VkImageUsageFlags usage, bool isProtected)
|
VkSamplerYcbcrConversion ycbcrConversion, bool isExternalFormat, VkImageUsageFlags usage,
|
||||||
|
bool isProtected)
|
||||||
: mStagePool(stagePool),
|
: mStagePool(stagePool),
|
||||||
mCommands(commands),
|
mCommands(commands),
|
||||||
mAllocator(allocator),
|
mAllocator(allocator),
|
||||||
@@ -233,17 +234,17 @@ VulkanTextureState::VulkanTextureState(VulkanStagePool& stagePool, VulkanCommand
|
|||||||
mVkFormat(format),
|
mVkFormat(format),
|
||||||
mViewType(viewType),
|
mViewType(viewType),
|
||||||
mFullViewRange{ fvkutils::getImageAspect(format), 0, levels, 0, layerCount },
|
mFullViewRange{ fvkutils::getImageAspect(format), 0, levels, 0, layerCount },
|
||||||
mYcbcr{ ycbcrConversion },
|
mYcbcr{ ycbcrConversion, isExternalFormat },
|
||||||
mDefaultLayout(getDefaultLayoutImpl(usage)),
|
mDefaultLayout(getDefaultLayoutImpl(usage)),
|
||||||
mUsage(usage),
|
mUsage(usage),
|
||||||
mIsProtected(isProtected) {}
|
mIsProtected(isProtected) {}
|
||||||
|
|
||||||
VulkanTextureState::~VulkanTextureState() {
|
VulkanTextureState::~VulkanTextureState() {
|
||||||
clearCachedImageViews();
|
|
||||||
if (mTextureImageMemory != VK_NULL_HANDLE) {
|
if (mTextureImageMemory != VK_NULL_HANDLE) {
|
||||||
vkDestroyImage(mDevice, mTextureImage, VKALLOC);
|
vkDestroyImage(mDevice, mTextureImage, VKALLOC);
|
||||||
vkFreeMemory(mDevice, mTextureImageMemory, VKALLOC);
|
vkFreeMemory(mDevice, mTextureImageMemory, VKALLOC);
|
||||||
}
|
}
|
||||||
|
clearCachedImageViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanTextureState::clearCachedImageViews() noexcept {
|
void VulkanTextureState::clearCachedImageViews() noexcept {
|
||||||
@@ -271,7 +272,7 @@ VkImageView VulkanTextureState::getImageView(VkImageSubresourceRange range, VkIm
|
|||||||
.flags = 0,
|
.flags = 0,
|
||||||
.image = mTextureImage,
|
.image = mTextureImage,
|
||||||
.viewType = viewType,
|
.viewType = viewType,
|
||||||
.format = mYcbcr.conversion != VK_NULL_HANDLE ? VK_FORMAT_UNDEFINED : mVkFormat,
|
.format = mYcbcr.isExternalFormat ? VK_FORMAT_UNDEFINED : mVkFormat,
|
||||||
.components = swizzle,
|
.components = swizzle,
|
||||||
.subresourceRange = range,
|
.subresourceRange = range,
|
||||||
};
|
};
|
||||||
@@ -293,6 +294,7 @@ VulkanTexture::VulkanTexture(VulkanContext const& context, VkDevice device, VmaA
|
|||||||
commands, allocator, device, image, memory, format,
|
commands, allocator, device, image, memory, format,
|
||||||
fvkutils::getViewType(SamplerType::SAMPLER_2D),
|
fvkutils::getViewType(SamplerType::SAMPLER_2D),
|
||||||
/*mipLevels=*/1, getLayerCountFromDepth(depth), conversion,
|
/*mipLevels=*/1, getLayerCountFromDepth(depth), conversion,
|
||||||
|
/*isExternalFormat=*/false,
|
||||||
getUsage(context, samples, VK_NULL_HANDLE, format, tusage),
|
getUsage(context, samples, VK_NULL_HANDLE, format, tusage),
|
||||||
any(usage & TextureUsage::PROTECTED))) {
|
any(usage & TextureUsage::PROTECTED))) {
|
||||||
mPrimaryViewRange = mState->mFullViewRange;
|
mPrimaryViewRange = mState->mFullViewRange;
|
||||||
@@ -422,7 +424,8 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
|||||||
mState = fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, stagePool,
|
mState = fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, stagePool,
|
||||||
commands, allocator, device, textureImage, textureImageMemory, vkFormat,
|
commands, allocator, device, textureImage, textureImageMemory, vkFormat,
|
||||||
fvkutils::getViewType(target), levels, getLayerCount(target, depth),
|
fvkutils::getViewType(target), levels, getLayerCount(target, depth),
|
||||||
VK_NULL_HANDLE /* ycbcrConversion */, imageInfo.usage, isProtected);
|
VK_NULL_HANDLE /* ycbcrConversion */, false /*isExternalFormat*/, imageInfo.usage,
|
||||||
|
isProtected);
|
||||||
|
|
||||||
// Spec out the "primary" VkImageView that shaders use to sample from the image.
|
// Spec out the "primary" VkImageView that shaders use to sample from the image.
|
||||||
mPrimaryViewRange = mState->mFullViewRange;
|
mPrimaryViewRange = mState->mFullViewRange;
|
||||||
@@ -761,13 +764,15 @@ void VulkanTexture::setLayout(VkImageSubresourceRange const& range, VulkanLayout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanTexture::setYcbcrConversion(VkSamplerYcbcrConversion conversion) {
|
void VulkanTexture::setYcbcrConversion(VkSamplerYcbcrConversion conversion, bool isExternalFormat) {
|
||||||
// Note that this comparison is valid because we only ever create VkSamplerYcbcrConversion from
|
// Note that this comparison is valid because we only ever create VkSamplerYcbcrConversion from
|
||||||
// a cache. So for each set of parameters, there is exactly one conversion (similar to
|
// a cache. So for each set of parameters, there is exactly one conversion (similar to
|
||||||
// samplers).
|
// samplers).
|
||||||
VulkanTextureState::Ycbcr ycbcr = {
|
VulkanTextureState::Ycbcr ycbcr = {
|
||||||
.conversion = conversion,
|
.conversion = conversion,
|
||||||
|
.isExternalFormat = isExternalFormat,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mState->mYcbcr != ycbcr) {
|
if (mState->mYcbcr != ycbcr) {
|
||||||
mState->mYcbcr = ycbcr;
|
mState->mYcbcr = ycbcr;
|
||||||
mState->clearCachedImageViews();
|
mState->clearCachedImageViews();
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ struct VulkanTextureState : public fvkmemory::Resource {
|
|||||||
VulkanTextureState(VulkanStagePool& stagePool, VulkanCommands* commands, VmaAllocator allocator,
|
VulkanTextureState(VulkanStagePool& stagePool, VulkanCommands* commands, VmaAllocator allocator,
|
||||||
VkDevice device, VkImage image, VkDeviceMemory deviceMemory, VkFormat format,
|
VkDevice device, VkImage image, VkDeviceMemory deviceMemory, VkFormat format,
|
||||||
VkImageViewType viewType, uint8_t levels, uint8_t layerCount,
|
VkImageViewType viewType, uint8_t levels, uint8_t layerCount,
|
||||||
VkSamplerYcbcrConversion ycbcrConversion, VkImageUsageFlags usage, bool isProtected);
|
VkSamplerYcbcrConversion ycbcrConversion, bool isExternalFormat,
|
||||||
|
VkImageUsageFlags usage, bool isProtected);
|
||||||
|
|
||||||
~VulkanTextureState();
|
~VulkanTextureState();
|
||||||
|
|
||||||
@@ -85,9 +86,10 @@ private:
|
|||||||
// conversion matrix per-frame.
|
// conversion matrix per-frame.
|
||||||
struct Ycbcr {
|
struct Ycbcr {
|
||||||
VkSamplerYcbcrConversion conversion;
|
VkSamplerYcbcrConversion conversion;
|
||||||
|
bool isExternalFormat;
|
||||||
|
|
||||||
bool operator==(Ycbcr const& other) const {
|
bool operator==(Ycbcr const& other) const {
|
||||||
return conversion == other.conversion;
|
return conversion == other.conversion && isExternalFormat == other.isExternalFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(Ycbcr const& other) const {
|
bool operator!=(Ycbcr const& other) const {
|
||||||
@@ -207,7 +209,7 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
|||||||
// This is used in the case of external images and external samplers. AHB might update the
|
// This is used in the case of external images and external samplers. AHB might update the
|
||||||
// conversion per-frame. This implies that we need to invalidate the view cache when that
|
// conversion per-frame. This implies that we need to invalidate the view cache when that
|
||||||
// happens.
|
// happens.
|
||||||
void setYcbcrConversion(VkSamplerYcbcrConversion conversion);
|
void setYcbcrConversion(VkSamplerYcbcrConversion conversion, bool isExternal);
|
||||||
|
|
||||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||||
void print() const;
|
void print() const;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ VulkanYcbcrConversionCache::VulkanYcbcrConversionCache(VkDevice device)
|
|||||||
: mDevice(device) {}
|
: mDevice(device) {}
|
||||||
|
|
||||||
VkSamplerYcbcrConversion VulkanYcbcrConversionCache::getConversion(
|
VkSamplerYcbcrConversion VulkanYcbcrConversionCache::getConversion(
|
||||||
VulkanYcbcrConversionCache::Params params) {
|
VulkanYcbcrConversionCache::Params params) noexcept {
|
||||||
auto iter = mCache.find(params);
|
auto iter = mCache.find(params);
|
||||||
if (UTILS_LIKELY(iter != mCache.end())) {
|
if (UTILS_LIKELY(iter != mCache.end())) {
|
||||||
return iter->second;
|
return iter->second;
|
||||||
@@ -43,7 +43,7 @@ VkSamplerYcbcrConversion VulkanYcbcrConversionCache::getConversion(
|
|||||||
TextureSwizzle const swizzleArray[] = { chroma.r, chroma.g, chroma.b, chroma.a };
|
TextureSwizzle const swizzleArray[] = { chroma.r, chroma.g, chroma.b, chroma.a };
|
||||||
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
|
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
|
||||||
.format = params.format,
|
.format = fvkutils::getVkFormat(params.format),
|
||||||
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
|
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
|
||||||
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
|
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
|
||||||
.components = fvkutils::getSwizzleMap(swizzleArray),
|
.components = fvkutils::getSwizzleMap(swizzleArray),
|
||||||
|
|||||||
@@ -30,14 +30,15 @@ namespace filament::backend {
|
|||||||
class VulkanYcbcrConversionCache {
|
class VulkanYcbcrConversionCache {
|
||||||
public:
|
public:
|
||||||
struct Params {
|
struct Params {
|
||||||
SamplerYcbcrConversion conversion = {}; // 4
|
SamplerYcbcrConversion conversion = {};
|
||||||
VkFormat format; // 4
|
TextureFormat format = {};
|
||||||
uint64_t externalFormat = 0; // 8
|
uint16_t padding = 0;
|
||||||
|
uint64_t externalFormat = 0;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Params) == 16);
|
static_assert(sizeof(Params) == 16);
|
||||||
|
|
||||||
explicit VulkanYcbcrConversionCache(VkDevice device);
|
explicit VulkanYcbcrConversionCache(VkDevice device);
|
||||||
VkSamplerYcbcrConversion getConversion(Params params);
|
VkSamplerYcbcrConversion getConversion(Params params) noexcept;
|
||||||
void terminate() noexcept;
|
void terminate() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -47,8 +48,7 @@ private:
|
|||||||
bool operator()(Params lhs, Params rhs) const noexcept {
|
bool operator()(Params lhs, Params rhs) const noexcept {
|
||||||
SamplerYcbcrConversion::EqualTo equal;
|
SamplerYcbcrConversion::EqualTo equal;
|
||||||
return equal(lhs.conversion, rhs.conversion) &&
|
return equal(lhs.conversion, rhs.conversion) &&
|
||||||
lhs.externalFormat == rhs.externalFormat &&
|
lhs.externalFormat == rhs.externalFormat;
|
||||||
lhs.format == rhs.format;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
using ConversionHashFn = utils::hash::MurmurHashFn<Params>;
|
using ConversionHashFn = utils::hash::MurmurHashFn<Params>;
|
||||||
|
|||||||
@@ -31,8 +31,6 @@ ResourceManager::ResourceManager(size_t arenaSize, bool disableUseAfterFreeCheck
|
|||||||
: mHandleAllocatorImpl("Handles", arenaSize, disableUseAfterFreeCheck, disablePoolHandleTags) {}
|
: mHandleAllocatorImpl("Handles", arenaSize, disableUseAfterFreeCheck, disablePoolHandleTags) {}
|
||||||
|
|
||||||
void ResourceManager::gc() noexcept {
|
void ResourceManager::gc() noexcept {
|
||||||
FVK_SYSTRACE_CONTEXT();
|
|
||||||
FVK_SYSTRACE_START("ResourceManager::gc");
|
|
||||||
auto destroyAll = [this](GcList& list) {
|
auto destroyAll = [this](GcList& list) {
|
||||||
for (auto const& [type, id]: list) {
|
for (auto const& [type, id]: list) {
|
||||||
destroyWithType(type, id);
|
destroyWithType(type, id);
|
||||||
@@ -51,7 +49,6 @@ void ResourceManager::gc() noexcept {
|
|||||||
GcList gcs;
|
GcList gcs;
|
||||||
std::swap(gcs, mGcList);
|
std::swap(gcs, mGcList);
|
||||||
destroyAll(gcs);
|
destroyAll(gcs);
|
||||||
FVK_SYSTRACE_END();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceManager::terminate() noexcept {
|
void ResourceManager::terminate() noexcept {
|
||||||
|
|||||||
@@ -132,10 +132,6 @@ public:
|
|||||||
return id() == other.id() && type() == other.type();
|
return id() == other.id() && type() == other.type();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator!=(resource_ptr<D> const& other) const {
|
|
||||||
return !((*this) == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline explicit operator bool() const {
|
inline explicit operator bool() const {
|
||||||
return bool(mRef);
|
return bool(mRef);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,8 +212,6 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
|||||||
VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
|
VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
|
||||||
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
|
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
|
||||||
VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
|
VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
|
||||||
// This is needed for external images. See VulkanPlatformAndroid
|
|
||||||
VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME,
|
|
||||||
#endif
|
#endif
|
||||||
// MoltenVk is the only non-conformant implementation we're interested in.
|
// MoltenVk is the only non-conformant implementation we're interested in.
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
@@ -995,6 +993,30 @@ VkQueue VulkanPlatform::getProtectedGraphicsQueue() const noexcept {
|
|||||||
return mImpl->mProtectedGraphicsQueue;
|
return mImpl->mProtectedGraphicsQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadata(
|
||||||
|
ExternalImageHandleRef externalImage) {
|
||||||
|
return getExternalImageMetadataImpl(externalImage, mImpl->mDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageData(
|
||||||
|
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata,
|
||||||
|
uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
||||||
|
return createExternalImageDataImpl(externalImage, mImpl->mDevice, metadata, memoryTypeIndex,
|
||||||
|
usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSampler VulkanPlatform::createExternalSampler(SamplerYcbcrConversion chroma,
|
||||||
|
SamplerParams sampler, uint32_t internalFormat) {
|
||||||
|
return createExternalSamplerImpl(mImpl->mDevice, chroma, sampler, internalFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView VulkanPlatform::createExternalImageView(SamplerYcbcrConversion chroma,
|
||||||
|
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
|
||||||
|
VkImageViewType viewType, VkComponentMapping swizzle) {
|
||||||
|
return createExternalImageViewImpl(mImpl->mDevice, chroma, internalFormat, image, range,
|
||||||
|
viewType, swizzle);
|
||||||
|
}
|
||||||
|
|
||||||
ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() const {
|
ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() const {
|
||||||
return getSwapchainInstanceExtensionsImpl();
|
return getSwapchainInstanceExtensionsImpl();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
#include <backend/platforms/VulkanPlatformAndroid.h>
|
#include <backend/platforms/VulkanPlatformAndroid.h>
|
||||||
|
|
||||||
#include "vulkan/VulkanConstants.h"
|
|
||||||
#include "vulkan/VulkanContext.h"
|
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <private/backend/BackendUtilsAndroid.h>
|
#include <private/backend/BackendUtilsAndroid.h>
|
||||||
|
|
||||||
|
#include "vulkan/VulkanConstants.h"
|
||||||
|
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include "vulkan/utils/Image.h"
|
#include "vulkan/utils/Image.h"
|
||||||
|
#include "vulkan/utils/Conversion.h"
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
@@ -39,14 +39,6 @@ namespace {
|
|||||||
|
|
||||||
VkFormat transformVkFormat(VkFormat format, bool sRGB) {
|
VkFormat transformVkFormat(VkFormat format, bool sRGB) {
|
||||||
if (!sRGB) {
|
if (!sRGB) {
|
||||||
switch (format) {
|
|
||||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
|
||||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
case VK_FORMAT_R8G8B8_SRGB:
|
|
||||||
return VK_FORMAT_R8G8B8_UNORM;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +57,7 @@ VkFormat transformVkFormat(VkFormat format, bool sRGB) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isProtectedFromUsage(uint64_t usage) {
|
bool isProtectedFromUsage(uint64_t usage) {
|
||||||
return usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
|
return (usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer_Desc& desc,
|
std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer_Desc& desc,
|
||||||
@@ -128,9 +120,7 @@ std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer
|
|||||||
usage = 0;
|
usage = 0;
|
||||||
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
|
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
|
||||||
usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||||
|
usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
||||||
// We shouldn't be using external samplers as input attachments
|
|
||||||
// usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
|
||||||
}
|
}
|
||||||
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
|
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
|
||||||
if (isDepthFormat) {
|
if (isDepthFormat) {
|
||||||
@@ -146,37 +136,87 @@ std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer
|
|||||||
return { format, usage };
|
return { format, usage };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<TextureFormat, TextureUsage> getFilamentFormatAndUsage(const AHardwareBuffer_Desc& desc,
|
VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevice device,
|
||||||
bool sRGB) {
|
VulkanPlatform::ExternalImageMetadata const& metadata, uint32_t memoryTypeIndex,
|
||||||
auto const format = mapToFilamentFormat(desc.format, sRGB);
|
VkImageUsageFlags usage) {
|
||||||
return {
|
VulkanPlatform::ImageData data;
|
||||||
format,
|
|
||||||
mapToFilamentUsage(desc.usage, format),
|
// if external format we need to specifiy it in the allocation
|
||||||
|
const bool useExternalFormat = metadata.format == VK_FORMAT_UNDEFINED;
|
||||||
|
|
||||||
|
const VkExternalFormatANDROID externalFormat = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
||||||
|
.pNext = nullptr,
|
||||||
|
// pass down the format (external means we don't have it VK defined)
|
||||||
|
.externalFormat = metadata.externalFormat,
|
||||||
};
|
};
|
||||||
|
const VkExternalMemoryImageCreateInfo externalCreateInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
||||||
|
.pNext = useExternalFormat ? &externalFormat : nullptr,
|
||||||
|
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkImageCreateInfo imageInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||||
|
imageInfo.pNext = &externalCreateInfo;
|
||||||
|
imageInfo.format = metadata.format;
|
||||||
|
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
imageInfo.extent = {
|
||||||
|
metadata.width,
|
||||||
|
metadata.height,
|
||||||
|
1u,
|
||||||
|
};
|
||||||
|
imageInfo.mipLevels = 1;
|
||||||
|
imageInfo.arrayLayers = metadata.layers;
|
||||||
|
imageInfo.samples = metadata.samples;
|
||||||
|
imageInfo.usage = usage;
|
||||||
|
|
||||||
|
VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &data.first);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
|
<< "vkCreateImage failed with error=" << static_cast<int32_t>(result);
|
||||||
|
|
||||||
|
// Allocate the memory
|
||||||
|
VkImportAndroidHardwareBufferInfoANDROID androidHardwareBufferInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.buffer = buffer,
|
||||||
|
};
|
||||||
|
VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
|
||||||
|
.pNext = &androidHardwareBufferInfo,
|
||||||
|
.image = data.first,
|
||||||
|
.buffer = VK_NULL_HANDLE,
|
||||||
|
};
|
||||||
|
VkMemoryAllocateInfo allocInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||||
|
.pNext = &memoryDedicatedAllocateInfo,
|
||||||
|
.allocationSize = metadata.allocationSize,
|
||||||
|
.memoryTypeIndex = memoryTypeIndex,
|
||||||
|
};
|
||||||
|
result = vkAllocateMemory(device, &allocInfo, VKALLOC, &data.second);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
|
<< "vkAllocateMemory failed with error=" << static_cast<int32_t>(result);
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
}// namespace
|
}// namespace
|
||||||
|
|
||||||
VulkanPlatformAndroid::ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() {
|
VulkanPlatformAndroid::ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
|
||||||
if (__builtin_available(android 26, *)) {
|
|
||||||
if (aHardwareBuffer) {
|
|
||||||
AHardwareBuffer_release(aHardwareBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
|
Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
|
||||||
AHardwareBuffer const* buffer, bool sRGB) noexcept {
|
AHardwareBuffer const* buffer, bool sRGB) noexcept {
|
||||||
if (__builtin_available(android 26, *)) {
|
if (__builtin_available(android 26, *)) {
|
||||||
auto bufferImpl = const_cast<AHardwareBuffer*>(buffer);
|
|
||||||
AHardwareBuffer_acquire(bufferImpl);
|
|
||||||
|
|
||||||
AHardwareBuffer_Desc hardwareBufferDescription = {};
|
AHardwareBuffer_Desc hardwareBufferDescription = {};
|
||||||
AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
|
AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
|
||||||
|
|
||||||
auto* const p = new (std::nothrow) ExternalImageVulkanAndroid;
|
auto* const p = new (std::nothrow) ExternalImageVulkanAndroid;
|
||||||
p->aHardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
|
p->aHardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
|
||||||
p->sRGB = sRGB;
|
p->sRGB = sRGB;
|
||||||
|
p->height = hardwareBufferDescription.height;
|
||||||
|
p->width = hardwareBufferDescription.width;
|
||||||
|
TextureFormat textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB);
|
||||||
|
p->format = textureFormat;
|
||||||
|
p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat);
|
||||||
return Platform::ExternalImageHandle{ p };
|
return Platform::ExternalImageHandle{ p };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,20 +225,23 @@ Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
|
|||||||
|
|
||||||
VulkanPlatformAndroid::ExternalImageDescAndroid VulkanPlatformAndroid::getExternalImageDesc(
|
VulkanPlatformAndroid::ExternalImageDescAndroid VulkanPlatformAndroid::getExternalImageDesc(
|
||||||
ExternalImageHandleRef externalImage) const noexcept {
|
ExternalImageHandleRef externalImage) const noexcept {
|
||||||
auto metadata = extractExternalImageMetadata(externalImage);
|
auto const* fvkExternalImage =
|
||||||
|
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
.width = metadata.width,
|
.width = fvkExternalImage->width,
|
||||||
.height = metadata.height,
|
.height = fvkExternalImage->height,
|
||||||
.format = metadata.filamentFormat,
|
.format = fvkExternalImage->format,
|
||||||
.usage = metadata.filamentUsage,
|
.usage = fvkExternalImage->usage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::extractExternalImageMetadata(
|
VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMetadata(
|
||||||
ExternalImageHandleRef image) const {
|
ExternalImageHandleRef externalImage) {
|
||||||
auto const* fvkExternalImage = static_cast<ExternalImageVulkanAndroid const*>(image.get());
|
auto const* fvkExternalImage =
|
||||||
|
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||||
|
|
||||||
ExternalImageMetadata metadata = {};
|
ExternalImageMetadata metadata;
|
||||||
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
|
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
|
||||||
if (__builtin_available(android 26, *)) {
|
if (__builtin_available(android 26, *)) {
|
||||||
AHardwareBuffer_Desc bufferDesc;
|
AHardwareBuffer_Desc bufferDesc;
|
||||||
@@ -206,29 +249,16 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::extractExternalImag
|
|||||||
metadata.width = bufferDesc.width;
|
metadata.width = bufferDesc.width;
|
||||||
metadata.height = bufferDesc.height;
|
metadata.height = bufferDesc.height;
|
||||||
metadata.layers = bufferDesc.layers;
|
metadata.layers = bufferDesc.layers;
|
||||||
|
metadata.isProtected = isProtectedFromUsage(bufferDesc.usage);
|
||||||
std::tie(metadata.format, metadata.usage) =
|
std::tie(metadata.format, metadata.usage) =
|
||||||
getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
|
getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
|
||||||
std::tie(metadata.filamentFormat, metadata.filamentUsage) =
|
|
||||||
getFilamentFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
|
|
||||||
|
|
||||||
if (isProtectedFromUsage(bufferDesc.usage)) {
|
|
||||||
metadata.filamentUsage |= TextureUsage::PROTECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: The following seems unnecessary. we should be able to discern directly from the
|
|
||||||
// bufferDesc.
|
|
||||||
if (any(metadata.filamentUsage & TextureUsage::BLIT_SRC)) {
|
|
||||||
metadata.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (any(metadata.filamentUsage & (TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE))) {
|
|
||||||
metadata.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata.samples = VK_SAMPLE_COUNT_1_BIT;
|
metadata.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
|
||||||
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
|
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
|
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
|
||||||
|
.pNext = nullptr,
|
||||||
};
|
};
|
||||||
VkAndroidHardwareBufferPropertiesANDROID properties = {
|
VkAndroidHardwareBufferPropertiesANDROID properties = {
|
||||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
|
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
|
||||||
@@ -238,155 +268,138 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::extractExternalImag
|
|||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "vkGetAndroidHardwareBufferProperties failed with error="
|
<< "vkGetAndroidHardwareBufferProperties failed with error="
|
||||||
<< static_cast<int32_t>(result);
|
<< static_cast<int32_t>(result);
|
||||||
|
|
||||||
VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB);
|
VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB);
|
||||||
FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat)
|
FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat)
|
||||||
<< "mismatched image format( " << metadata.format << ") and queried format("
|
<< "mismatched image format( " << metadata.format << ") and queried format("
|
||||||
<< bufferPropertiesFormat << ") for external image (AHB)";
|
<< bufferPropertiesFormat << ") for external image (AHB)";
|
||||||
|
metadata.externalFormat = formatInfo.externalFormat;
|
||||||
bool const requiresConversion =
|
|
||||||
metadata.format == VK_FORMAT_UNDEFINED ||
|
|
||||||
fvkutils::isVKYcbcrConversionFormat(metadata.format);
|
|
||||||
if (requiresConversion) {
|
|
||||||
metadata.format = VK_FORMAT_UNDEFINED;
|
|
||||||
metadata.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
||||||
metadata.externalFormat = formatInfo.externalFormat;
|
|
||||||
} else {
|
|
||||||
metadata.externalFormat = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata.allocationSize = properties.allocationSize;
|
metadata.allocationSize = properties.allocationSize;
|
||||||
metadata.memoryTypeBits = properties.memoryTypeBits;
|
metadata.memoryTypeBits = properties.memoryTypeBits;
|
||||||
|
|
||||||
metadata.ycbcrConversionComponents = formatInfo.samplerYcbcrConversionComponents;
|
|
||||||
metadata.ycbcrModel = formatInfo.suggestedYcbcrModel;
|
|
||||||
metadata.ycbcrRange = formatInfo.suggestedYcbcrRange;
|
|
||||||
metadata.xChromaOffset = formatInfo.suggestedXChromaOffset;
|
|
||||||
metadata.yChromaOffset = formatInfo.suggestedYChromaOffset;
|
|
||||||
|
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::ImageData VulkanPlatformAndroid::createVkImageFromExternal(
|
VulkanPlatformAndroid::ImageData VulkanPlatformAndroid::createExternalImageData(
|
||||||
ExternalImageHandleRef externalImage) const {
|
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata,
|
||||||
auto metadata = extractExternalImageMetadata(externalImage);
|
uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
||||||
|
|
||||||
auto const* fvkExternalImage =
|
auto const* fvkExternalImage =
|
||||||
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||||
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
|
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, getDevice(), metadata,
|
||||||
|
memoryTypeIndex, usage);
|
||||||
|
VkResult result = vkBindImageMemory(getDevice(), data.first, data.second, 0);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
|
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
VkDevice const device = getDevice();
|
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device, SamplerYcbcrConversion chroma,
|
||||||
VkPhysicalDevice const physicalDevice = getPhysicalDevice();
|
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
|
||||||
auto buildImage = [&](ExternalImageMetadata const& metadata) {
|
VkImageViewType viewType, VkComponentMapping swizzle){
|
||||||
bool const isExternal = metadata.externalFormat != 0;
|
VkExternalFormatANDROID externalFormat = {
|
||||||
VkExternalFormatANDROID const externalFormat = {
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
||||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
.externalFormat = internalFormat,
|
||||||
.pNext = nullptr,
|
|
||||||
.externalFormat = metadata.externalFormat,
|
|
||||||
};
|
|
||||||
VkExternalMemoryImageCreateInfo externalCreateInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
|
||||||
.pNext = isExternal ? &externalFormat : nullptr,
|
|
||||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkFormat formats[2] = {};
|
|
||||||
VkImageFormatListCreateInfo imageFormatListInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.viewFormatCount = 2,
|
|
||||||
.pViewFormats = formats,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (fvkExternalImage->sRGB) {
|
|
||||||
formats[0] = metadata.format;
|
|
||||||
formats[1] = transformVkFormat(metadata.format, /*sRGB=*/false);
|
|
||||||
imageFormatListInfo.pNext = externalCreateInfo.pNext;
|
|
||||||
externalCreateInfo.pNext = &imageFormatListInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageCreateInfo const imageInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
||||||
.pNext = &externalCreateInfo,
|
|
||||||
.flags = fvkExternalImage->sRGB ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0u,
|
|
||||||
.imageType = VK_IMAGE_TYPE_2D,
|
|
||||||
// For non external images, use the same format as the AHB, which isn't in SRGB
|
|
||||||
// Fix VUID-VkMemoryAllocateInfo-pNext-02387
|
|
||||||
.format = transformVkFormat(metadata.format, /*sRGB=*/false),
|
|
||||||
.extent = {
|
|
||||||
metadata.width,
|
|
||||||
metadata.height,
|
|
||||||
1u,
|
|
||||||
},
|
|
||||||
.mipLevels = 1,
|
|
||||||
.arrayLayers = metadata.layers,
|
|
||||||
.samples = metadata.samples,
|
|
||||||
.usage = metadata.usage,
|
|
||||||
};
|
|
||||||
VkImage image;
|
|
||||||
VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &image);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "vkCreateImage failed with error=" << static_cast<int32_t>(result);
|
|
||||||
return image;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto allocMem = [&](VkImage image, ExternalImageMetadata const& metadata) {
|
TextureSwizzle const swizzleArray[] = {chroma.r, chroma.g, chroma.b, chroma.a};
|
||||||
bool const isExternal = metadata.externalFormat != 0;
|
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
|
||||||
// Allocate the memory
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
|
||||||
VkImportAndroidHardwareBufferInfoANDROID const androidHardwareBufferInfo = {
|
.pNext = &externalFormat,
|
||||||
.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
|
.format = VK_FORMAT_UNDEFINED,
|
||||||
.buffer = buffer,
|
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
|
||||||
};
|
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
|
||||||
VkMemoryDedicatedAllocateInfo const memoryDedicatedAllocateInfo = {
|
.components = fvkutils::getSwizzleMap(swizzleArray),
|
||||||
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
|
.xChromaOffset = fvkutils::getChromaLocation(chroma.xChromaOffset),
|
||||||
.pNext = &androidHardwareBufferInfo,
|
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
|
||||||
.image = image,
|
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
|
||||||
.buffer = VK_NULL_HANDLE,
|
};
|
||||||
};
|
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
|
||||||
VkPhysicalDeviceMemoryProperties memoryProperties;
|
VkResult result = vkCreateSamplerYcbcrConversion(device, &conversionInfo,
|
||||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
|
nullptr, &conversion);
|
||||||
VkMemoryPropertyFlags requiredMemoryFlags =
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
!isExternal && any(metadata.filamentUsage & TextureUsage::UPLOADABLE)
|
<< "Unable to create Ycbcr Conversion."
|
||||||
? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
<< " error=" << static_cast<int32_t>(result);
|
||||||
: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
|
||||||
|
|
||||||
if (any(metadata.filamentUsage & TextureUsage::PROTECTED)) {
|
VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {
|
||||||
requiredMemoryFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
|
||||||
}
|
.conversion = conversion,
|
||||||
|
|
||||||
uint32_t const memoryTypeIndex = VulkanContext::selectMemoryType(memoryProperties,
|
|
||||||
metadata.memoryTypeBits, requiredMemoryFlags);
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo const allocInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
||||||
.pNext = &memoryDedicatedAllocateInfo,
|
|
||||||
.allocationSize = metadata.allocationSize,
|
|
||||||
.memoryTypeIndex = memoryTypeIndex,
|
|
||||||
};
|
|
||||||
VkDeviceMemory memory;
|
|
||||||
VkResult result = vkAllocateMemory(device, &allocInfo, VKALLOC, &memory);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "vkAllocateMemory failed with error=" << static_cast<int32_t>(result);
|
|
||||||
result = vkBindImageMemory(getDevice(), image, memory, 0);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
|
|
||||||
return memory;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
VulkanPlatform::ImageData::Bundle internal = {}, external = {};
|
VkImageViewCreateInfo viewInfo = {
|
||||||
auto img = buildImage(metadata);
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||||
auto mem = allocMem(img, metadata);
|
.pNext = &samplerYcbcrConversionInfo,
|
||||||
|
.flags = 0,
|
||||||
// Note that we're always choosing a non-externally sampled format if it exists.
|
.image = image,
|
||||||
if (metadata.externalFormat == 0) {
|
.viewType = viewType,
|
||||||
internal = { img, mem };
|
.format = VK_FORMAT_UNDEFINED,
|
||||||
} else {
|
.components = swizzle,
|
||||||
external = { img, mem };
|
.subresourceRange = range,
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
.internal = internal,
|
|
||||||
.external = external,
|
|
||||||
};
|
};
|
||||||
|
VkImageView imageView;
|
||||||
|
result = vkCreateImageView(device, &viewInfo, VKALLOC, &imageView);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
|
<< "Unable to create VkImageView."
|
||||||
|
<< " error=" << static_cast<int32_t>(result);
|
||||||
|
|
||||||
|
return imageView;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSampler VulkanPlatform::createExternalSamplerImpl(
|
||||||
|
VkDevice device, SamplerYcbcrConversion chroma, SamplerParams params,
|
||||||
|
uint32_t internalFormat) {
|
||||||
|
VkExternalFormatANDROID externalFormat = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
||||||
|
.externalFormat = internalFormat,
|
||||||
|
};
|
||||||
|
|
||||||
|
TextureSwizzle const swizzleArray[] = {chroma.r, chroma.g, chroma.b, chroma.a};
|
||||||
|
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
|
||||||
|
.pNext = &externalFormat,
|
||||||
|
.format = VK_FORMAT_UNDEFINED,
|
||||||
|
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
|
||||||
|
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
|
||||||
|
.components = fvkutils::getSwizzleMap(swizzleArray),
|
||||||
|
.xChromaOffset = fvkutils::getChromaLocation(chroma.xChromaOffset),
|
||||||
|
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
|
||||||
|
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
|
||||||
|
};
|
||||||
|
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
|
||||||
|
VkResult result = vkCreateSamplerYcbcrConversion(device, &conversionInfo,
|
||||||
|
nullptr, &conversion);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
|
<< "Unable to create Ycbcr Conversion."
|
||||||
|
<< " error=" << static_cast<int32_t>(result);
|
||||||
|
|
||||||
|
VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.conversion = conversion,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkSamplerCreateInfo samplerInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||||
|
.pNext = &samplerYcbcrConversionInfo,
|
||||||
|
.magFilter = fvkutils::getFilter(params.filterMag),
|
||||||
|
.minFilter = fvkutils::getFilter(params.filterMin),
|
||||||
|
.mipmapMode = fvkutils::getMipmapMode(params.filterMin),
|
||||||
|
.addressModeU = fvkutils::getWrapMode(params.wrapS),
|
||||||
|
.addressModeV = fvkutils::getWrapMode(params.wrapT),
|
||||||
|
.addressModeW = fvkutils::getWrapMode(params.wrapR),
|
||||||
|
.anisotropyEnable = params.anisotropyLog2 == 0 ? VK_FALSE : VK_TRUE,
|
||||||
|
.maxAnisotropy = (float)(1u << params.anisotropyLog2),
|
||||||
|
.compareEnable = fvkutils::getCompareEnable(params.compareMode),
|
||||||
|
.compareOp = fvkutils::getCompareOp(params.compareFunc),
|
||||||
|
.minLod = 0.0f,
|
||||||
|
.maxLod = fvkutils::getMaxLod(params.filterMin),
|
||||||
|
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
||||||
|
.unnormalizedCoordinates = VK_FALSE,
|
||||||
|
};
|
||||||
|
VkSampler sampler;
|
||||||
|
result = vkCreateSampler(device, &samplerInfo, VKALLOC, &sampler);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
|
<< "Unable to create sampler."
|
||||||
|
<< " error=" << static_cast<int32_t>(result);
|
||||||
|
return sampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::ExtensionSet VulkanPlatformAndroid::getSwapchainInstanceExtensions() const {
|
VulkanPlatform::ExtensionSet VulkanPlatformAndroid::getSwapchainInstanceExtensions() const {
|
||||||
@@ -400,7 +413,7 @@ VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* na
|
|||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
VkExtent2D extent;
|
VkExtent2D extent;
|
||||||
|
|
||||||
VkAndroidSurfaceCreateInfoKHR const createInfo = {
|
VkAndroidSurfaceCreateInfoKHR const createInfo{
|
||||||
.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
|
||||||
.window = (ANativeWindow*) nativeWindow,
|
.window = (ANativeWindow*) nativeWindow,
|
||||||
};
|
};
|
||||||
@@ -414,9 +427,20 @@ VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* na
|
|||||||
// Deprecated platform dependent helper methods
|
// Deprecated platform dependent helper methods
|
||||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() { return {}; }
|
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() { return {}; }
|
||||||
|
|
||||||
|
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||||
|
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||||
|
return ExternalImageMetadata{};
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||||
|
ExternalImageHandleRef externalImage, VkDevice device,
|
||||||
|
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
||||||
|
return ImageData{};
|
||||||
|
}
|
||||||
|
|
||||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
|
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
|
||||||
VkInstance instance, uint64_t flags) noexcept {
|
VkInstance instance, uint64_t flags) noexcept {
|
||||||
return SurfaceBundle{};
|
return SurfaceBundle{};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace filament::backend
|
}// namespace filament::backend
|
||||||
|
|||||||
@@ -43,6 +43,30 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||||
|
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||||
|
ExternalImageHandleRef externalImage, VkDevice device,
|
||||||
|
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSampler VulkanPlatform::createExternalSamplerImpl(VkDevice device,
|
||||||
|
SamplerYcbcrConversion chroma,
|
||||||
|
SamplerParams sampler,
|
||||||
|
uint32_t internalFormat) {
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
|
||||||
|
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
||||||
|
VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle) {
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
|
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
|
||||||
VkInstance instance, uint64_t flags) noexcept {
|
VkInstance instance, uint64_t flags) noexcept {
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
|
|||||||
@@ -84,6 +84,30 @@ using namespace bluevk;
|
|||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
|
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||||
|
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||||
|
ExternalImageHandleRef externalImage, VkDevice device,
|
||||||
|
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSampler VulkanPlatform::createExternalSamplerImpl(VkDevice device,
|
||||||
|
SamplerYcbcrConversion chroma,
|
||||||
|
SamplerParams sampler,
|
||||||
|
uint32_t internalFormat) {
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
|
||||||
|
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
||||||
|
VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle) {
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() {
|
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() {
|
||||||
VulkanPlatform::ExtensionSet const ret = {
|
VulkanPlatform::ExtensionSet const ret = {
|
||||||
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||||
|
|||||||
@@ -51,8 +51,6 @@ VkFormat getVkFormat(ElementType type, bool normalized, bool integer) {
|
|||||||
return VK_FORMAT_UNDEFINED;
|
return VK_FORMAT_UNDEFINED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-normalized case
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
// Single Component Types
|
// Single Component Types
|
||||||
case ElementType::BYTE: return integer ? VK_FORMAT_R8_SINT : VK_FORMAT_R8_SSCALED;
|
case ElementType::BYTE: return integer ? VK_FORMAT_R8_SINT : VK_FORMAT_R8_SSCALED;
|
||||||
|
|||||||
@@ -184,46 +184,6 @@ bool isVkStencilFormat(VkFormat format) {
|
|||||||
return (getImageAspect(format) & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
|
return (getImageAspect(format) & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isVKYcbcrConversionFormat(VkFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case VK_FORMAT_G8B8G8R8_422_UNORM:
|
|
||||||
case VK_FORMAT_B8G8R8G8_422_UNORM:
|
|
||||||
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
|
|
||||||
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
|
|
||||||
case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
|
|
||||||
case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
|
|
||||||
case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
|
|
||||||
case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
|
|
||||||
case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
|
|
||||||
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
|
|
||||||
case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
|
|
||||||
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G16B16G16R16_422_UNORM:
|
|
||||||
case VK_FORMAT_B16G16R16G16_422_UNORM:
|
|
||||||
case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
|
|
||||||
case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
|
|
||||||
case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
|
|
||||||
case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
|
|
||||||
case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
|
|
||||||
case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
|
|
||||||
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
|
|
||||||
case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t mostSignificantBit(uint32_t x) { return 1ul << (31ul - utils::clz(x)); }
|
static uint32_t mostSignificantBit(uint32_t x) { return 1ul << (31ul - utils::clz(x)); }
|
||||||
|
|
||||||
uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask) {
|
uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask) {
|
||||||
|
|||||||
@@ -98,8 +98,6 @@ bool isVkDepthFormat(VkFormat format);
|
|||||||
|
|
||||||
bool isVkStencilFormat(VkFormat format);
|
bool isVkStencilFormat(VkFormat format);
|
||||||
|
|
||||||
bool isVKYcbcrConversionFormat(VkFormat format);
|
|
||||||
|
|
||||||
VkImageAspectFlags getImageAspect(VkFormat format);
|
VkImageAspectFlags getImageAspect(VkFormat format);
|
||||||
|
|
||||||
uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask);
|
uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@
|
|||||||
#include "webgpu/WebGPUDriver.h"
|
#include "webgpu/WebGPUDriver.h"
|
||||||
|
|
||||||
#include "WebGPUSwapChain.h"
|
#include "WebGPUSwapChain.h"
|
||||||
|
#include "webgpu/WebGPUConstants.h"
|
||||||
#include <backend/platforms/WebGPUPlatform.h>
|
#include <backend/platforms/WebGPUPlatform.h>
|
||||||
|
|
||||||
#include "CommandStreamDispatcher.h"
|
#include "CommandStreamDispatcher.h"
|
||||||
@@ -183,6 +184,8 @@ void printAdapterDetails(wgpu::Adapter const& adapter) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||||
void printDeviceDetails(wgpu::Device const& device) {
|
void printDeviceDetails(wgpu::Device const& device) {
|
||||||
wgpu::SupportedFeatures supportedFeatures{};
|
wgpu::SupportedFeatures supportedFeatures{};
|
||||||
@@ -234,7 +237,6 @@ WebGPUDriver::WebGPUDriver(WebGPUPlatform& platform, const Platform::DriverConfi
|
|||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||||
printDeviceDetails(mDevice);
|
printDeviceDetails(mDevice);
|
||||||
#endif
|
#endif
|
||||||
mQueue = mDevice.GetQueue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebGPUDriver::~WebGPUDriver() noexcept = default;
|
WebGPUDriver::~WebGPUDriver() noexcept = default;
|
||||||
@@ -317,9 +319,6 @@ void WebGPUDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
|
void WebGPUDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
|
||||||
if (boh) {
|
|
||||||
destructHandle<WGPUBufferObject>(boh);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyTexture(Handle<HwTexture> th) {
|
void WebGPUDriver::destroyTexture(Handle<HwTexture> th) {
|
||||||
@@ -354,9 +353,6 @@ void WebGPUDriver::destroyDescriptorSetLayout(Handle<HwDescriptorSetLayout> tqh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) {
|
void WebGPUDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) {
|
||||||
if (tqh) {
|
|
||||||
destructHandle<WebGPUDescriptorSet>(tqh);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwSwapChain> WebGPUDriver::createSwapChainS() noexcept {
|
Handle<HwSwapChain> WebGPUDriver::createSwapChainS() noexcept {
|
||||||
@@ -408,7 +404,7 @@ Handle<HwVertexBuffer> WebGPUDriver::createVertexBufferS() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwDescriptorSet> WebGPUDriver::createDescriptorSetS() noexcept {
|
Handle<HwDescriptorSet> WebGPUDriver::createDescriptorSetS() noexcept {
|
||||||
return allocHandle<WebGPUDescriptorSet>();
|
return Handle<HwDescriptorSet>((Handle<HwDescriptorSet>::HandleId) mNextFakeHandle++);
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwRenderPrimitive> WebGPUDriver::createRenderPrimitiveS() noexcept {
|
Handle<HwRenderPrimitive> WebGPUDriver::createRenderPrimitiveS() noexcept {
|
||||||
@@ -448,6 +444,7 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
|||||||
assert_invariant(!mSwapChain);
|
assert_invariant(!mSwapChain);
|
||||||
wgpu::Surface surface = mPlatform.createSurface(nativeWindow, flags);
|
wgpu::Surface surface = mPlatform.createSurface(nativeWindow, flags);
|
||||||
|
|
||||||
|
mQueue = mDevice.GetQueue();
|
||||||
wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow);
|
wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow);
|
||||||
mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter,
|
mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter,
|
||||||
mDevice, flags);
|
mDevice, flags);
|
||||||
@@ -470,27 +467,16 @@ void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t wi
|
|||||||
uint32_t height, uint64_t flags) {}
|
uint32_t height, uint64_t flags) {}
|
||||||
|
|
||||||
void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
|
void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
|
||||||
uint8_t attributeCount, AttributeArray attributes) {
|
uint8_t attributeCount, AttributeArray attributes) {}
|
||||||
constructHandle<WGPUVertexBufferInfo>(vbih, bufferCount, attributeCount, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
|
void WebGPUDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
|
||||||
Handle<HwVertexBufferInfo> vbih) {
|
Handle<HwVertexBufferInfo> vbih) {}
|
||||||
auto* vertexBufferInfo = handleCast<WGPUVertexBufferInfo>(vbih);
|
|
||||||
constructHandle<WGPUVertexBuffer>(vbh, mDevice, vertexCount, vertexBufferInfo->bufferCount,
|
|
||||||
vbih);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
void WebGPUDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
||||||
uint32_t indexCount, BufferUsage usage) {
|
uint32_t indexCount, BufferUsage usage) {}
|
||||||
auto elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
|
|
||||||
constructHandle<WGPUIndexBuffer>(ibh, mDevice, elementSize, indexCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||||
BufferObjectBinding bindingType, BufferUsage usage) {
|
BufferObjectBinding bindingType, BufferUsage usage) {}
|
||||||
constructHandle<WGPUBufferObject>(boh, mDevice, bindingType, byteCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
void WebGPUDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||||
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
||||||
@@ -520,16 +506,7 @@ void WebGPUDriver::importTextureR(Handle<HwTexture> th, intptr_t id, SamplerType
|
|||||||
uint32_t depth, TextureUsage usage) {}
|
uint32_t depth, TextureUsage usage) {}
|
||||||
|
|
||||||
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<HwVertexBuffer> vbh,
|
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<HwVertexBuffer> vbh,
|
||||||
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {
|
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {}
|
||||||
assert_invariant(mDevice);
|
|
||||||
|
|
||||||
auto* renderPrimitive = constructHandle<WGPURenderPrimitive>(rph);
|
|
||||||
auto* vertexBuffer = handleCast<WGPUVertexBuffer>(vbh);
|
|
||||||
auto* indexBuffer = handleCast<WGPUIndexBuffer>(ibh);
|
|
||||||
renderPrimitive->vertexBuffer = vertexBuffer;
|
|
||||||
renderPrimitive->indexBuffer = indexBuffer;
|
|
||||||
renderPrimitive->type = pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
|
void WebGPUDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
|
||||||
constructHandle<WGPUProgram>(ph, mDevice, program);
|
constructHandle<WGPUProgram>(ph, mDevice, program);
|
||||||
@@ -555,10 +532,7 @@ void WebGPUDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
||||||
Handle<HwDescriptorSetLayout> dslh) {
|
Handle<HwDescriptorSetLayout> dslh) {}
|
||||||
auto layout = handleCast<WebGPUDescriptorSetLayout>(dslh);
|
|
||||||
constructHandle<WebGPUDescriptorSet>(dsh, layout->getLayout(), layout->getLayoutSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
|
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
|
||||||
return {};
|
return {};
|
||||||
@@ -598,7 +572,7 @@ bool WebGPUDriver::isTextureFormatSupported(TextureFormat format) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WebGPUDriver::isTextureSwizzleSupported() {
|
bool WebGPUDriver::isTextureSwizzleSupported() {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebGPUDriver::isTextureFormatMipmappable(TextureFormat format) {
|
bool WebGPUDriver::isTextureFormatMipmappable(TextureFormat format) {
|
||||||
@@ -687,21 +661,20 @@ size_t WebGPUDriver::getMaxArrayTextureLayers() {
|
|||||||
|
|
||||||
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||||
uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
updateGPUBuffer(handleCast<WGPUIndexBuffer>(ibh), std::move(p), byteOffset);
|
scheduleDestroy(std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::updateBufferObject(Handle<HwBufferObject> ibh, BufferDescriptor&& p,
|
void WebGPUDriver::updateBufferObject(Handle<HwBufferObject> ibh, BufferDescriptor&& p,
|
||||||
uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
updateGPUBuffer(handleCast<WGPUBufferObject>(ibh), std::move(p), byteOffset);
|
scheduleDestroy(std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> ibh,
|
void WebGPUDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> ibh, BufferDescriptor&& p,
|
||||||
BufferDescriptor&& p, uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
updateGPUBuffer(handleCast<WGPUBufferObject>(ibh), std::move(p), byteOffset);
|
scheduleDestroy(std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::resetBufferObject(Handle<HwBufferObject> boh) {
|
void WebGPUDriver::resetBufferObject(Handle<HwBufferObject> boh) {
|
||||||
// Is there something that needs to be done here? Vulkan has left it unimplemented.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
|
void WebGPUDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
|
||||||
@@ -709,8 +682,7 @@ void WebGPUDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t in
|
|||||||
auto* vertexBuffer = handleCast<WGPUVertexBuffer>(vbh);
|
auto* vertexBuffer = handleCast<WGPUVertexBuffer>(vbh);
|
||||||
auto* bufferObject = handleCast<WGPUBufferObject>(boh);
|
auto* bufferObject = handleCast<WGPUBufferObject>(boh);
|
||||||
assert_invariant(index < vertexBuffer->buffers.size());
|
assert_invariant(index < vertexBuffer->buffers.size());
|
||||||
assert_invariant(bufferObject->buffer.GetUsage() & wgpu::BufferUsage::Vertex);
|
vertexBuffer->setBuffer(bufferObject, index);
|
||||||
vertexBuffer->buffers[index] = bufferObject->buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::update3DImage(Handle<HwTexture> th,
|
void WebGPUDriver::update3DImage(Handle<HwTexture> th,
|
||||||
@@ -748,7 +720,6 @@ void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
|||||||
};
|
};
|
||||||
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
|
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
|
||||||
assert_invariant(mCommandEncoder);
|
assert_invariant(mCommandEncoder);
|
||||||
|
|
||||||
// TODO: Remove this code once WebGPU pipeline is implemented
|
// TODO: Remove this code once WebGPU pipeline is implemented
|
||||||
static float red = 1.0f;
|
static float red = 1.0f;
|
||||||
if (red - 0.01 > 0) {
|
if (red - 0.01 > 0) {
|
||||||
@@ -862,19 +833,6 @@ void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||||
auto* renderPrimitive = handleCast<WGPURenderPrimitive>(rph);
|
|
||||||
|
|
||||||
// This *must* match the WGPUVertexBufferInfo that was bound in bindPipeline(). But we want
|
|
||||||
// to allow to call this before bindPipeline(), so the validation can only happen in draw()
|
|
||||||
auto vbi = handleCast<WGPUVertexBufferInfo>(renderPrimitive->vertexBuffer->vbih);
|
|
||||||
assert_invariant(
|
|
||||||
vbi->getVertexBufferLayoutSize() == renderPrimitive->vertexBuffer->buffers.size());
|
|
||||||
for (uint32_t i = 0; i < vbi->getVertexBufferLayoutSize(); i++) {
|
|
||||||
mRenderPassEncoder.SetVertexBuffer(i, renderPrimitive->vertexBuffer->buffers[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
mRenderPassEncoder.SetIndexBuffer(renderPrimitive->indexBuffer->buffer,
|
|
||||||
renderPrimitive->indexBuffer->indexFormat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
void WebGPUDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
||||||
@@ -900,48 +858,25 @@ void WebGPUDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
|
|||||||
void WebGPUDriver::resetState(int) {
|
void WebGPUDriver::resetState(int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::updateDescriptorSetBuffer(Handle<HwDescriptorSet> dsh,
|
void WebGPUDriver::updateDescriptorSetBuffer(
|
||||||
backend::descriptor_binding_t binding, Handle<HwBufferObject> boh, uint32_t offset,
|
Handle<HwDescriptorSet> dsh,
|
||||||
|
backend::descriptor_binding_t binding,
|
||||||
|
Handle<HwBufferObject> boh,
|
||||||
|
uint32_t offset,
|
||||||
uint32_t size) {
|
uint32_t size) {
|
||||||
auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
|
||||||
auto buffer = handleCast<WGPUBufferObject>(boh);
|
|
||||||
if (!bindGroup->getIsLocked()) {
|
|
||||||
// TODO making assumptions that size and offset mean the same thing here.
|
|
||||||
wgpu::BindGroupEntry entry{ .binding = static_cast<uint32_t>(binding * 2),
|
|
||||||
.buffer = buffer->buffer,
|
|
||||||
.offset = offset,
|
|
||||||
.size = size };
|
|
||||||
bindGroup->addEntry(entry.binding, std::move(entry));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::updateDescriptorSetTexture(Handle<HwDescriptorSet> dsh,
|
void WebGPUDriver::updateDescriptorSetTexture(
|
||||||
backend::descriptor_binding_t binding, Handle<HwTexture> th, SamplerParams params) {
|
Handle<HwDescriptorSet> dsh,
|
||||||
/*
|
backend::descriptor_binding_t binding,
|
||||||
auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
Handle<HwTexture> th,
|
||||||
auto texture = handleCast<WGPUTexture>(th);
|
SamplerParams params) {
|
||||||
|
|
||||||
// TODO very high odds badd assumptions are in here about handling HwTexture. Revisit with more
|
|
||||||
// understanding. Right now assuming there is a wgpu::TextureView filled in
|
|
||||||
if (!bindGroup->getIsLocked()) {
|
|
||||||
// TODO making assumptions that size and offset mean the same thing here.
|
|
||||||
wgpu::BindGroupEntry tEntry{ .binding = static_cast<uint32_t>(binding * 2),
|
|
||||||
.textureView = texture->texView };
|
|
||||||
bindGroup->addEntry(tEntry.binding, std::move(tEntry));
|
|
||||||
|
|
||||||
wgpu::BindGroupEntry sEntry{ .binding = static_cast<uint32_t>(binding * 2 + 1),
|
|
||||||
.sampler = texture->sampler };
|
|
||||||
bindGroup->addEntry(sEntry.binding, std::move(sEntry));
|
|
||||||
}
|
|
||||||
//TODO Just the setup, this function stilll needs the rest of logic implemented
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> dsh, backend::descriptor_set_t set,
|
void WebGPUDriver::bindDescriptorSet(
|
||||||
|
Handle<HwDescriptorSet> dsh,
|
||||||
|
backend::descriptor_set_t set,
|
||||||
backend::DescriptorSetOffsetArray&& offsets) {
|
backend::DescriptorSetOffsetArray&& offsets) {
|
||||||
auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
|
||||||
// TODO: presume we need this, use it. Probably Encoder::SetBindGroup
|
|
||||||
auto wbg = bindGroup->lockAndReturn(mDevice);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
|
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#define TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
#define TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
||||||
|
|
||||||
#include "WebGPUHandles.h"
|
#include "WebGPUHandles.h"
|
||||||
#include "webgpu/WebGPUConstants.h"
|
|
||||||
#include <backend/platforms/WebGPUPlatform.h>
|
#include <backend/platforms/WebGPUPlatform.h>
|
||||||
|
|
||||||
#include "DriverBase.h"
|
#include "DriverBase.h"
|
||||||
@@ -35,7 +34,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#ifndef FILAMENT_WEBGPU_HANDLE_ARENA_SIZE_IN_MB
|
#ifndef FILAMENT_WEBGPU_HANDLE_ARENA_SIZE_IN_MB
|
||||||
#define FILAMENT_WEBGPU_HANDLE_ARENA_SIZE_IN_MB 8
|
# define FILAMENT_WEBGPU_HANDLE_ARENA_SIZE_IN_MB 8
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
@@ -57,27 +56,6 @@ private:
|
|||||||
[[nodiscard]] ShaderModel getShaderModel() const noexcept final;
|
[[nodiscard]] ShaderModel getShaderModel() const noexcept final;
|
||||||
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
|
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
|
||||||
|
|
||||||
template<typename GPUBufferObject>
|
|
||||||
void updateGPUBuffer(GPUBufferObject* gpuBufferObject, BufferDescriptor&& bufferDescriptor,
|
|
||||||
uint32_t byteOffset) {
|
|
||||||
FILAMENT_CHECK_PRECONDITION(bufferDescriptor.buffer)
|
|
||||||
<< "copyIntoBuffer called with a null buffer";
|
|
||||||
FILAMENT_CHECK_PRECONDITION(
|
|
||||||
bufferDescriptor.size + byteOffset <= gpuBufferObject->buffer.GetSize())
|
|
||||||
<< "Attempting to copy " << bufferDescriptor.size << " bytes into a buffer of size "
|
|
||||||
<< gpuBufferObject->buffer.GetSize() << " at offset " << byteOffset;
|
|
||||||
|
|
||||||
// TODO: All buffer objects are created with CopyDst usage.
|
|
||||||
// This may have some performance implications. That should be investigated later.
|
|
||||||
assert_invariant(gpuBufferObject->buffer.GetUsage() & wgpu::BufferUsage::CopyDst);
|
|
||||||
|
|
||||||
// WriteBuffer is an async call. But cpu buffer data is already written to the staging
|
|
||||||
// buffer on return from the WriteBuffer.
|
|
||||||
mQueue.WriteBuffer(gpuBufferObject->buffer, byteOffset, bufferDescriptor.buffer,
|
|
||||||
bufferDescriptor.size);
|
|
||||||
scheduleDestroy(std::move(bufferDescriptor));
|
|
||||||
}
|
|
||||||
|
|
||||||
// the platform (e.g. OS) specific aspects of the WebGPU backend are strictly only
|
// the platform (e.g. OS) specific aspects of the WebGPU backend are strictly only
|
||||||
// handled in the WebGPUPlatform
|
// handled in the WebGPUPlatform
|
||||||
WebGPUPlatform& mPlatform;
|
WebGPUPlatform& mPlatform;
|
||||||
@@ -121,8 +99,8 @@ private:
|
|||||||
return mHandleAllocator.allocate<D>();
|
return mHandleAllocator.allocate<D>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename D, typename B, typename... ARGS>
|
template<typename D, typename B, typename ... ARGS>
|
||||||
D* constructHandle(Handle<B>& handle, ARGS&&... args) noexcept {
|
D* constructHandle(Handle<B>& handle, ARGS&& ... args) noexcept {
|
||||||
return mHandleAllocator.construct<D>(handle, std::forward<ARGS>(args)...);
|
return mHandleAllocator.construct<D>(handle, std::forward<ARGS>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +112,7 @@ private:
|
|||||||
template<typename D, typename B>
|
template<typename D, typename B>
|
||||||
void destructHandle(Handle<B>& handle) noexcept {
|
void destructHandle(Handle<B>& handle) noexcept {
|
||||||
auto* p = mHandleAllocator.handle_cast<D*>(handle);
|
auto* p = mHandleAllocator.handle_cast<D*>(handle);
|
||||||
mHandleAllocator.deallocate(handle, p);
|
return mHandleAllocator.deallocate(handle, p);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
* Copyright (C) 2025 The Android Open Source Project
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -19,159 +19,46 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr wgpu::BufferUsage getBufferObjectUsage(
|
|
||||||
filament::backend::BufferObjectBinding bindingType) noexcept {
|
|
||||||
switch (bindingType) {
|
|
||||||
case filament::backend::BufferObjectBinding::VERTEX:
|
|
||||||
return wgpu::BufferUsage::Vertex;
|
|
||||||
case filament::backend::BufferObjectBinding::UNIFORM:
|
|
||||||
return wgpu::BufferUsage::Uniform;
|
|
||||||
case filament::backend::BufferObjectBinding::SHADER_STORAGE:
|
|
||||||
return wgpu::BufferUsage::Storage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wgpu::Buffer createBuffer(wgpu::Device const& device, wgpu::BufferUsage usage, uint32_t size,
|
wgpu::Buffer createIndexBuffer(wgpu::Device const& device, uint8_t elementSize, uint32_t indexCount) {
|
||||||
char const* label) {
|
wgpu::BufferDescriptor descriptor{ .label = "index_buffer",
|
||||||
wgpu::BufferDescriptor descriptor{ .label = label,
|
.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Index,
|
||||||
.usage = usage,
|
.size = elementSize * indexCount,
|
||||||
.size = size,
|
|
||||||
.mappedAtCreation = false };
|
.mappedAtCreation = false };
|
||||||
return device.CreateBuffer(&descriptor);
|
return device.CreateBuffer(&descriptor);
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
wgpu::VertexFormat getVertexFormat(filament::backend::ElementType type, bool normalized, bool integer) {
|
|
||||||
using ElementType = filament::backend::ElementType;
|
|
||||||
using VertexFormat = wgpu::VertexFormat;
|
|
||||||
if (normalized) {
|
|
||||||
switch (type) {
|
|
||||||
// Single Component Types
|
|
||||||
case ElementType::BYTE: return VertexFormat::Snorm8;
|
|
||||||
case ElementType::UBYTE: return VertexFormat::Unorm8;
|
|
||||||
case ElementType::SHORT: return VertexFormat::Snorm16;
|
|
||||||
case ElementType::USHORT: return VertexFormat::Unorm16;
|
|
||||||
// Two Component Types
|
|
||||||
case ElementType::BYTE2: return VertexFormat::Snorm8x2;
|
|
||||||
case ElementType::UBYTE2: return VertexFormat::Unorm8x2;
|
|
||||||
case ElementType::SHORT2: return VertexFormat::Snorm16x2;
|
|
||||||
case ElementType::USHORT2: return VertexFormat::Unorm16x2;
|
|
||||||
// Three Component Types
|
|
||||||
// There is no vertex format type for 3 byte data in webgpu. Use
|
|
||||||
// 4 byte signed normalized type and ignore the last byte.
|
|
||||||
// TODO: This is to be verified.
|
|
||||||
case ElementType::BYTE3: return VertexFormat::Snorm8x4; // NOT MINSPEC
|
|
||||||
case ElementType::UBYTE3: return VertexFormat::Unorm8x4; // NOT MINSPEC
|
|
||||||
case ElementType::SHORT3: return VertexFormat::Snorm16x4; // NOT MINSPEC
|
|
||||||
case ElementType::USHORT3: return VertexFormat::Unorm16x4; // NOT MINSPEC
|
|
||||||
// Four Component Types
|
|
||||||
case ElementType::BYTE4: return VertexFormat::Snorm8x4;
|
|
||||||
case ElementType::UBYTE4: return VertexFormat::Unorm8x4;
|
|
||||||
case ElementType::SHORT4: return VertexFormat::Snorm16x4;
|
|
||||||
case ElementType::USHORT4: return VertexFormat::Unorm8x4;
|
|
||||||
default:
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(false) << "Normalized format does not exist.";
|
|
||||||
return VertexFormat::Float32x3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (type) {
|
|
||||||
// Single Component Types
|
|
||||||
// There is no direct alternative for SSCALED in webgpu. Convert them to Float32 directly.
|
|
||||||
// This will result in increased memory on the cpu side.
|
|
||||||
// TODO: Is Float16 acceptable instead with some potential accuracy errors?
|
|
||||||
case ElementType::BYTE: return integer ? VertexFormat::Sint8 : VertexFormat::Float32;
|
|
||||||
case ElementType::UBYTE: return integer ? VertexFormat::Uint8 : VertexFormat::Float32;
|
|
||||||
case ElementType::SHORT: return integer ? VertexFormat::Sint16 : VertexFormat::Float32;
|
|
||||||
case ElementType::USHORT: return integer ? VertexFormat::Uint16 : VertexFormat::Float32;
|
|
||||||
case ElementType::HALF: return VertexFormat::Float16;
|
|
||||||
case ElementType::INT: return VertexFormat::Sint32;
|
|
||||||
case ElementType::UINT: return VertexFormat::Uint32;
|
|
||||||
case ElementType::FLOAT: return VertexFormat::Float32;
|
|
||||||
// Two Component Types
|
|
||||||
case ElementType::BYTE2: return integer ? VertexFormat::Sint8x2 : VertexFormat::Float32x2;
|
|
||||||
case ElementType::UBYTE2: return integer ? VertexFormat::Uint8x2 : VertexFormat::Float32x2;
|
|
||||||
case ElementType::SHORT2: return integer ? VertexFormat::Sint16x2 : VertexFormat::Float32x2;
|
|
||||||
case ElementType::USHORT2: return integer ? VertexFormat::Uint16x2 : VertexFormat::Float32x2;
|
|
||||||
case ElementType::HALF2: return VertexFormat::Float16x2;
|
|
||||||
case ElementType::FLOAT2: return VertexFormat::Float32x2;
|
|
||||||
// Three Component Types
|
|
||||||
case ElementType::BYTE3: return VertexFormat::Sint8x4; // NOT MINSPEC
|
|
||||||
case ElementType::UBYTE3: return VertexFormat::Uint8x4; // NOT MINSPEC
|
|
||||||
case ElementType::SHORT3: return VertexFormat::Sint16x4; // NOT MINSPEC
|
|
||||||
case ElementType::USHORT3: return VertexFormat::Uint16x4; // NOT MINSPEC
|
|
||||||
case ElementType::HALF3: return VertexFormat::Float16x4; // NOT MINSPEC
|
|
||||||
case ElementType::FLOAT3: return VertexFormat::Float32x3;
|
|
||||||
// Four Component Types
|
|
||||||
case ElementType::BYTE4: return integer ? VertexFormat::Sint8x4 : VertexFormat::Float32x4;
|
|
||||||
case ElementType::UBYTE4: return integer ? VertexFormat::Uint8x4 : VertexFormat::Float32x4;
|
|
||||||
case ElementType::SHORT4: return integer ? VertexFormat::Sint16x4 : VertexFormat::Float32x4;
|
|
||||||
case ElementType::USHORT4: return integer ? VertexFormat::Uint16x4 : VertexFormat::Float32x4;
|
|
||||||
case ElementType::HALF4: return VertexFormat::Float16x4;
|
|
||||||
case ElementType::FLOAT4: return VertexFormat::Float32x4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}// namespace
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
WGPUVertexBufferInfo::WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount,
|
|
||||||
AttributeArray const& attributes)
|
|
||||||
: HwVertexBufferInfo(bufferCount, attributeCount),
|
|
||||||
mVertexBufferLayout(bufferCount),
|
|
||||||
mAttributes(bufferCount) {
|
|
||||||
assert_invariant(attributeCount > 0);
|
|
||||||
assert_invariant(bufferCount > 0);
|
|
||||||
for (uint32_t attribIndex = 0; attribIndex < attributes.size(); attribIndex++) {
|
|
||||||
Attribute const& attrib = attributes[attribIndex];
|
|
||||||
// Ignore the attributes which are not bind to vertex buffers.
|
|
||||||
if (attrib.buffer == Attribute::BUFFER_UNUSED) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_invariant(attrib.buffer < bufferCount);
|
|
||||||
bool const isInteger = attrib.flags & Attribute::FLAG_INTEGER_TARGET;
|
|
||||||
bool const isNormalized = attrib.flags & Attribute::FLAG_NORMALIZED;
|
|
||||||
wgpu::VertexFormat vertexFormat = getVertexFormat(attrib.type, isNormalized, isInteger);
|
|
||||||
|
|
||||||
// Attributes are sequential per buffer
|
|
||||||
mAttributes[attrib.buffer].push_back({
|
|
||||||
.format = vertexFormat,
|
|
||||||
.offset = attrib.offset,
|
|
||||||
.shaderLocation = static_cast<uint32_t>(mAttributes[attrib.buffer].size()),
|
|
||||||
});
|
|
||||||
|
|
||||||
mVertexBufferLayout[attrib.buffer].stepMode = wgpu::VertexStepMode::Vertex;
|
|
||||||
if (mVertexBufferLayout[attrib.buffer].arrayStride == 0) {
|
|
||||||
mVertexBufferLayout[attrib.buffer].arrayStride = attrib.stride;
|
|
||||||
} else {
|
|
||||||
assert_invariant(mVertexBufferLayout[attrib.buffer].arrayStride == attrib.stride);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t bufferIndex = 0; bufferIndex < bufferCount; bufferIndex++) {
|
|
||||||
mVertexBufferLayout[bufferIndex].attributeCount = mAttributes[bufferIndex].size();
|
|
||||||
mVertexBufferLayout[bufferIndex].attributes = mAttributes[bufferIndex].data();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WGPUIndexBuffer::WGPUIndexBuffer(wgpu::Device const& device, uint8_t elementSize,
|
WGPUIndexBuffer::WGPUIndexBuffer(wgpu::Device const& device, uint8_t elementSize,
|
||||||
uint32_t indexCount)
|
uint32_t indexCount)
|
||||||
: buffer(createBuffer(device, wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Index,
|
: buffer(createIndexBuffer(device, elementSize, indexCount)) {}
|
||||||
elementSize * indexCount, "index_buffer")),
|
|
||||||
indexFormat(elementSize == 2 ? wgpu::IndexFormat::Uint16 : wgpu::IndexFormat::Uint32) {}
|
|
||||||
|
|
||||||
|
|
||||||
WGPUVertexBuffer::WGPUVertexBuffer(wgpu::Device const& device, uint32_t vertexCount,
|
WGPUVertexBuffer::WGPUVertexBuffer(wgpu::Device const &device, uint32_t vextexCount, uint32_t bufferCount,
|
||||||
uint32_t bufferCount, Handle<HwVertexBufferInfo> vbih)
|
Handle<WGPUVertexBufferInfo> vbih)
|
||||||
: HwVertexBuffer(vertexCount),
|
: HwVertexBuffer(vextexCount),
|
||||||
vbih(vbih),
|
vbih(vbih),
|
||||||
buffers(bufferCount) {}
|
buffers(bufferCount) {
|
||||||
|
wgpu::BufferDescriptor descriptor {
|
||||||
|
.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Vertex,
|
||||||
|
.size = vextexCount * bufferCount,
|
||||||
|
.mappedAtCreation = false };
|
||||||
|
|
||||||
WGPUBufferObject::WGPUBufferObject(wgpu::Device const& device, BufferObjectBinding bindingType,
|
for (uint32_t i = 0; i < bufferCount; ++i) {
|
||||||
uint32_t byteCount)
|
descriptor.label = ("vertex_buffer_" + std::to_string(i)).c_str();
|
||||||
|
buffers[i] = device.CreateBuffer(&descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Empty function is a place holder for verxtex buffer updates and should be
|
||||||
|
// updated for that purpose.
|
||||||
|
void WGPUVertexBuffer::setBuffer(WGPUBufferObject* bufferObject, uint32_t index) {}
|
||||||
|
|
||||||
|
WGPUBufferObject::WGPUBufferObject(BufferObjectBinding bindingType, uint32_t byteCount)
|
||||||
: HwBufferObject(byteCount),
|
: HwBufferObject(byteCount),
|
||||||
buffer(createBuffer(device, wgpu::BufferUsage::CopyDst | getBufferObjectUsage(bindingType),
|
|
||||||
byteCount, "buffer_object")),
|
|
||||||
bufferObjectBinding(bindingType) {}
|
bufferObjectBinding(bindingType) {}
|
||||||
|
|
||||||
wgpu::ShaderStage WebGPUDescriptorSetLayout::filamentStageToWGPUStage(ShaderStageFlags fFlags) {
|
wgpu::ShaderStage WebGPUDescriptorSetLayout::filamentStageToWGPUStage(ShaderStageFlags fFlags) {
|
||||||
@@ -259,39 +146,7 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
|||||||
.entries = wEntries.data()
|
.entries = wEntries.data()
|
||||||
};
|
};
|
||||||
// TODO Do we need to defer this until we have more info on textures and samplers??
|
// TODO Do we need to defer this until we have more info on textures and samplers??
|
||||||
mLayoutSize = wEntries.size();
|
|
||||||
mLayout = device.CreateBindGroupLayout(&layoutDescriptor);
|
mLayout = device.CreateBindGroupLayout(&layoutDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebGPUDescriptorSetLayout::~WebGPUDescriptorSetLayout() {}
|
WebGPUDescriptorSetLayout::~WebGPUDescriptorSetLayout() {}
|
||||||
|
|
||||||
WebGPUDescriptorSet::WebGPUDescriptorSet(const wgpu::BindGroupLayout& layout, uint layoutSize)
|
|
||||||
: mLayout(layout),
|
|
||||||
entries(layoutSize, wgpu::BindGroupEntry{}) {
|
|
||||||
// Establish the size of entries based on the layout. This should be reliable and efficient.
|
|
||||||
}
|
|
||||||
WebGPUDescriptorSet::~WebGPUDescriptorSet() {}
|
|
||||||
|
|
||||||
wgpu::BindGroup WebGPUDescriptorSet::lockAndReturn(const wgpu::Device& device) {
|
|
||||||
if (mBindGroup) {
|
|
||||||
return mBindGroup;
|
|
||||||
}
|
|
||||||
// TODO label? Should we just copy layout label?
|
|
||||||
wgpu::BindGroupDescriptor desc{ .layout = mLayout,
|
|
||||||
.entryCount = entries.size(),
|
|
||||||
.entries = entries.data() };
|
|
||||||
mBindGroup = device.CreateBindGroup(&desc);
|
|
||||||
return mBindGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDescriptorSet::addEntry(uint index, wgpu::BindGroupEntry&& entry) {
|
|
||||||
if (mBindGroup) {
|
|
||||||
// We will keep getting hits from future updates, but shouldn't do anything
|
|
||||||
// Filament guarantees this won't change after things have locked.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// TODO: Putting some level of trust that Filament is not going to reuse indexes or go past the
|
|
||||||
// layout index for efficiency. Add guards if wrong.
|
|
||||||
entries[index] = std::move(entry);
|
|
||||||
}
|
|
||||||
}// namespace filament::backend
|
}// namespace filament::backend
|
||||||
|
|||||||
@@ -43,44 +43,23 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct WGPUBufferObject;
|
struct WGPUBufferObject;
|
||||||
|
// TODO: Currently WGPUVertexBufferInfo is not used by WebGPU for useful task.
|
||||||
// VertexBufferInfo contains layout info for Vertex Buffer based on WebGPU structs. In WebGPU each
|
// Update the struct when used by WebGPU driver.
|
||||||
// VertexBufferLayout is associated with a single vertex buffer. So number of mVertexBufferLayout
|
struct WGPUVertexBufferInfo : public HwVertexBufferInfo {
|
||||||
// is equal to bufferCount. Each VertexBufferLayout can contain multiple VertexAttribute. Bind index
|
|
||||||
// of vertex buffer is implicitly calculated by the position of VertexBufferLayout in an array.
|
|
||||||
class WGPUVertexBufferInfo : public HwVertexBufferInfo {
|
|
||||||
public:
|
|
||||||
WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount,
|
WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount,
|
||||||
AttributeArray const& attributes);
|
AttributeArray const& attributes)
|
||||||
inline wgpu::VertexBufferLayout const* getVertexBufferLayout() const {
|
: HwVertexBufferInfo(bufferCount, attributeCount),
|
||||||
return mVertexBufferLayout.data();
|
attributes(attributes) {}
|
||||||
}
|
AttributeArray attributes;
|
||||||
|
|
||||||
inline uint32_t getVertexBufferLayoutSize() const {
|
|
||||||
return mVertexBufferLayout.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline wgpu::VertexAttribute const* getVertexAttributeForIndex(uint32_t index) const {
|
|
||||||
assert_invariant(index < mAttributes.size());
|
|
||||||
return mAttributes[index].data();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32_t getVertexAttributeSize(uint32_t index) const {
|
|
||||||
assert_invariant(index < mAttributes.size());
|
|
||||||
return mAttributes[index].size();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// TODO: can we do better in terms on heap management.
|
|
||||||
std::vector<wgpu::VertexBufferLayout> mVertexBufferLayout {};
|
|
||||||
std::vector<std::vector<wgpu::VertexAttribute>> mAttributes {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WGPUVertexBuffer : public HwVertexBuffer {
|
struct WGPUVertexBuffer : public HwVertexBuffer {
|
||||||
WGPUVertexBuffer(wgpu::Device const &device, uint32_t vertexCount, uint32_t bufferCount,
|
WGPUVertexBuffer(wgpu::Device const &device, uint32_t vextexCount, uint32_t bufferCount,
|
||||||
Handle<HwVertexBufferInfo> vbih);
|
Handle<WGPUVertexBufferInfo> vbih);
|
||||||
|
|
||||||
Handle<HwVertexBufferInfo> vbih;
|
void setBuffer(WGPUBufferObject *bufferObject, uint32_t index);
|
||||||
|
|
||||||
|
Handle<WGPUVertexBufferInfo> vbih;
|
||||||
utils::FixedCapacityVector<wgpu::Buffer> buffers;
|
utils::FixedCapacityVector<wgpu::Buffer> buffers;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -89,49 +68,29 @@ struct WGPUIndexBuffer : public HwIndexBuffer {
|
|||||||
uint32_t indexCount);
|
uint32_t indexCount);
|
||||||
|
|
||||||
wgpu::Buffer buffer;
|
wgpu::Buffer buffer;
|
||||||
wgpu::IndexFormat indexFormat;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Currently WGPUVertexBufferInfo is not used by WebGPU for useful task.
|
||||||
|
// Update the struct when used by WebGPU driver.
|
||||||
struct WGPUBufferObject : HwBufferObject {
|
struct WGPUBufferObject : HwBufferObject {
|
||||||
WGPUBufferObject(wgpu::Device const &device, BufferObjectBinding bindingType, uint32_t byteCount);
|
WGPUBufferObject(BufferObjectBinding bindingType, uint32_t byteCount);
|
||||||
|
|
||||||
wgpu::Buffer buffer = nullptr;
|
wgpu::Buffer buffer;
|
||||||
const BufferObjectBinding bufferObjectBinding;
|
const BufferObjectBinding bufferObjectBinding;
|
||||||
};
|
};
|
||||||
class WebGPUDescriptorSetLayout final : public HwDescriptorSetLayout {
|
class WebGPUDescriptorSetLayout : public HwDescriptorSetLayout {
|
||||||
public:
|
public:
|
||||||
WebGPUDescriptorSetLayout(DescriptorSetLayout const& layout, wgpu::Device const& device);
|
WebGPUDescriptorSetLayout(DescriptorSetLayout const& layout, wgpu::Device const& device);
|
||||||
~WebGPUDescriptorSetLayout();
|
~WebGPUDescriptorSetLayout();
|
||||||
[[nodiscard]] const wgpu::BindGroupLayout& getLayout() const { return mLayout; }
|
|
||||||
[[nodiscard]] uint getLayoutSize() const { return mLayoutSize; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO: If this is useful elsewhere, remove it from this class
|
// TODO: If this is useful elsewhere, remove it from this class
|
||||||
// Convert Filament Shader Stage Flags bitmask to webgpu equivilant
|
// Convert Filament Shader Stage Flags bitmask to webgpu equivilant
|
||||||
static wgpu::ShaderStage filamentStageToWGPUStage(ShaderStageFlags fFlags);
|
static wgpu::ShaderStage filamentStageToWGPUStage(ShaderStageFlags fFlags);
|
||||||
uint mLayoutSize;
|
|
||||||
wgpu::BindGroupLayout mLayout;
|
wgpu::BindGroupLayout mLayout;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WebGPUDescriptorSet final : public HwDescriptorSet {
|
|
||||||
public:
|
|
||||||
WebGPUDescriptorSet(const wgpu::BindGroupLayout& layout, uint layoutSize);
|
|
||||||
~WebGPUDescriptorSet();
|
|
||||||
|
|
||||||
wgpu::BindGroup lockAndReturn(wgpu::Device const& device);
|
|
||||||
void addEntry(uint index, wgpu::BindGroupEntry&& entry);
|
|
||||||
[[nodiscard]] bool getIsLocked() const { return mBindGroup != nullptr; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
// TODO: Consider storing what we used to make the layout. However we need to essentially
|
|
||||||
// Recreate some of the info (Sampler in slot X with the actual sampler) so letting Dawn confirm
|
|
||||||
// there isn't a mismatch may be easiest.
|
|
||||||
// Also storing the wgpu ObjectBase takes care of ownership challenges in theory
|
|
||||||
wgpu::BindGroupLayout mLayout;
|
|
||||||
std::vector<wgpu::BindGroupEntry> entries;
|
|
||||||
wgpu::BindGroup mBindGroup;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Currently WGPUTexture is not used by WebGPU for useful task.
|
// TODO: Currently WGPUTexture is not used by WebGPU for useful task.
|
||||||
// Update the struct when used by WebGPU driver.
|
// Update the struct when used by WebGPU driver.
|
||||||
struct WGPUTexture : public HwTexture {
|
struct WGPUTexture : public HwTexture {
|
||||||
@@ -142,15 +101,10 @@ struct WGPUTexture : public HwTexture {
|
|||||||
WGPUTexture(WGPUTexture const* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
WGPUTexture(WGPUTexture const* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
||||||
|
|
||||||
wgpu::Texture texture = nullptr;
|
wgpu::Texture texture = nullptr;
|
||||||
// TODO: Adding this but not yet setting it up. Filament "Textures" are combined image samplers,
|
|
||||||
// rep both.
|
|
||||||
wgpu::Sampler sampler = nullptr;
|
|
||||||
//TODO: Not sure all the ways HwTexture is used. Overloading like this might be entirely wrong.
|
|
||||||
wgpu::TextureView texView = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WGPURenderPrimitive : public HwRenderPrimitive {
|
struct WGPURenderPrimitive : public HwRenderPrimitive {
|
||||||
WGPURenderPrimitive() {}
|
WGPURenderPrimitive();
|
||||||
|
|
||||||
void setBuffers(WGPUVertexBufferInfo const* const vbi,
|
void setBuffers(WGPUVertexBufferInfo const* const vbi,
|
||||||
WGPUVertexBuffer* vertexBuffer, WGPUIndexBuffer* indexBuffer);
|
WGPUVertexBuffer* vertexBuffer, WGPUIndexBuffer* indexBuffer);
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ ssize_t BufferInterfaceBlock::getTransformFieldOffset(uint8_t binding) const {
|
|||||||
if (pos == mTransformOffsetMap.end()) {
|
if (pos == mTransformOffsetMap.end()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return (ssize_t)pos->second * sizeof(uint32_t);
|
return (ssize_t)pos->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferInterfaceBlock::FieldInfo const* BufferInterfaceBlock::getFieldInfo(
|
BufferInterfaceBlock::FieldInfo const* BufferInterfaceBlock::getFieldInfo(
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h> // memcpy
|
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|||||||
@@ -259,11 +259,10 @@ public:
|
|||||||
return normalize(lerp(d < 0 ? -p : p, q, t));
|
return normalize(lerp(d < 0 ? -p : p, q, t));
|
||||||
}
|
}
|
||||||
const T npq = std::sqrt(dot(p, p) * dot(q, q)); // ||p|| * ||q||
|
const T npq = std::sqrt(dot(p, p) * dot(q, q)); // ||p|| * ||q||
|
||||||
const T cos_a = math::clamp(absd / npq, T(-1), T(1));
|
const T a = std::acos(math::clamp(absd / npq, T(-1), T(1)));
|
||||||
const T a = std::acos(cos_a);
|
|
||||||
const T a0 = a * (1 - t);
|
const T a0 = a * (1 - t);
|
||||||
const T a1 = a * t;
|
const T a1 = a * t;
|
||||||
const T sina = std::sqrt(T(1) - cos_a * cos_a);
|
const T sina = sin(a);
|
||||||
if (sina < value_eps) {
|
if (sina < value_eps) {
|
||||||
return normalize(lerp(p, q, t));
|
return normalize(lerp(p, q, t));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,11 +122,6 @@ struct is_arithmetic : std::integral_constant<bool,
|
|||||||
std::is_integral<T>::value || std::is_floating_point<T>::value> {
|
std::is_integral<T>::value || std::is_floating_point<T>::value> {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct is_floating_point : std::integral_constant<bool,
|
|
||||||
std::is_floating_point<T>::value> {
|
|
||||||
};
|
|
||||||
|
|
||||||
} // filament::math
|
} // filament::math
|
||||||
|
|
||||||
#endif // TNT_MATH_COMPILER_H
|
#endif // TNT_MATH_COMPILER_H
|
||||||
|
|||||||
@@ -166,18 +166,18 @@ inline constexpr half operator""_h(long double v) {
|
|||||||
|
|
||||||
template<> struct is_arithmetic<half> : public std::true_type {};
|
template<> struct is_arithmetic<half> : public std::true_type {};
|
||||||
|
|
||||||
template<> struct is_floating_point<half> : public std::true_type {};
|
|
||||||
|
|
||||||
} // namespace math
|
} // namespace math
|
||||||
} // namespace filament
|
} // namespace filament
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
||||||
// Remove the standard template specializations for filament::math::half
|
template<> struct is_floating_point<filament::math::half> : public std::true_type {};
|
||||||
// Clang 20 explicitly blocks customizing standard type traits
|
|
||||||
// Instead, use the traits defined in the math:: namespace
|
// note: this shouldn't be needed (is_floating_point<> is enough) but some version of msvc need it
|
||||||
// This avoids compatibility issues with Clang 20 and MSVC 2019 16.4+
|
// This stopped working with MSVC 2019 16.4, so we specialize our own version of is_arithmetic in
|
||||||
// the math::filament namespace (see above).
|
// the math::filament namespace (see above).
|
||||||
|
template<> struct is_arithmetic<filament::math::half> : public std::true_type {};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class numeric_limits<filament::math::half> {
|
class numeric_limits<filament::math::half> {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -560,7 +560,7 @@ public:
|
|||||||
switch (0) \
|
switch (0) \
|
||||||
case 0: \
|
case 0: \
|
||||||
default: \
|
default: \
|
||||||
UTILS_VERY_LIKELY(cond) ? (void)0 : ::utils::details::Voidify()&&
|
UTILS_LIKELY(cond) ? (void)0 : ::utils::details::Voidify()&&
|
||||||
|
|
||||||
#define FILAMENT_PANIC_IMPL(message, TYPE) \
|
#define FILAMENT_PANIC_IMPL(message, TYPE) \
|
||||||
::utils::details::TPanicStream<::utils::TYPE>(PANIC_FUNCTION, PANIC_FILE(__FILE__), __LINE__, message)
|
::utils::details::TPanicStream<::utils::TYPE>(PANIC_FUNCTION, PANIC_FILE(__FILE__), __LINE__, message)
|
||||||
@@ -629,14 +629,14 @@ public:
|
|||||||
* @param format printf-style string describing the error in more details
|
* @param format printf-style string describing the error in more details
|
||||||
*/
|
*/
|
||||||
#define ASSERT_PRECONDITION(cond, format, ...) \
|
#define ASSERT_PRECONDITION(cond, format, ...) \
|
||||||
(!UTILS_VERY_LIKELY(cond) ? PANIC_PRECONDITION_IMPL(cond, format, ##__VA_ARGS__) : (void)0)
|
(!UTILS_LIKELY(cond) ? PANIC_PRECONDITION_IMPL(cond, format, ##__VA_ARGS__) : (void)0)
|
||||||
|
|
||||||
#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG)
|
#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG)
|
||||||
#define ASSERT_PRECONDITION_NON_FATAL(cond, format, ...) \
|
#define ASSERT_PRECONDITION_NON_FATAL(cond, format, ...) \
|
||||||
(!UTILS_VERY_LIKELY(cond) ? PANIC_PRECONDITION_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
(!UTILS_LIKELY(cond) ? PANIC_PRECONDITION_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
||||||
#else
|
#else
|
||||||
#define ASSERT_PRECONDITION_NON_FATAL(cond, format, ...) \
|
#define ASSERT_PRECONDITION_NON_FATAL(cond, format, ...) \
|
||||||
(!UTILS_VERY_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
(!UTILS_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -657,14 +657,14 @@ public:
|
|||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
#define ASSERT_POSTCONDITION(cond, format, ...) \
|
#define ASSERT_POSTCONDITION(cond, format, ...) \
|
||||||
(!UTILS_VERY_LIKELY(cond) ? PANIC_POSTCONDITION_IMPL(cond, format, ##__VA_ARGS__) : (void)0)
|
(!UTILS_LIKELY(cond) ? PANIC_POSTCONDITION_IMPL(cond, format, ##__VA_ARGS__) : (void)0)
|
||||||
|
|
||||||
#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG)
|
#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG)
|
||||||
#define ASSERT_POSTCONDITION_NON_FATAL(cond, format, ...) \
|
#define ASSERT_POSTCONDITION_NON_FATAL(cond, format, ...) \
|
||||||
(!UTILS_VERY_LIKELY(cond) ? PANIC_POSTCONDITION_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
(!UTILS_LIKELY(cond) ? PANIC_POSTCONDITION_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
||||||
#else
|
#else
|
||||||
#define ASSERT_POSTCONDITION_NON_FATAL(cond, format, ...) \
|
#define ASSERT_POSTCONDITION_NON_FATAL(cond, format, ...) \
|
||||||
(!UTILS_VERY_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
(!UTILS_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -689,10 +689,10 @@ public:
|
|||||||
|
|
||||||
#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG)
|
#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG)
|
||||||
#define ASSERT_ARITHMETIC_NON_FATAL(cond, format, ...) \
|
#define ASSERT_ARITHMETIC_NON_FATAL(cond, format, ...) \
|
||||||
(!UTILS_VERY_LIKELY(cond) ? PANIC_ARITHMETIC_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
(!UTILS_LIKELY(cond) ? PANIC_ARITHMETIC_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
||||||
#else
|
#else
|
||||||
#define ASSERT_ARITHMETIC_NON_FATAL(cond, format, ...) \
|
#define ASSERT_ARITHMETIC_NON_FATAL(cond, format, ...) \
|
||||||
(!UTILS_VERY_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
(!UTILS_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__), false : true)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -717,6 +717,6 @@ public:
|
|||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
#define ASSERT_DESTRUCTOR(cond, format, ...) \
|
#define ASSERT_DESTRUCTOR(cond, format, ...) \
|
||||||
(!UTILS_VERY_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__) : (void)0)
|
(!UTILS_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__) : (void)0)
|
||||||
|
|
||||||
#endif // TNT_UTILS_PANIC_H
|
#endif // TNT_UTILS_PANIC_H
|
||||||
|
|||||||
@@ -104,19 +104,6 @@
|
|||||||
# define UTILS_UNLIKELY( exp ) (!!(exp))
|
# define UTILS_UNLIKELY( exp ) (!!(exp))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_builtin(__builtin_expect_with_probability)
|
|
||||||
# ifdef __cplusplus
|
|
||||||
# define UTILS_VERY_LIKELY( exp ) (__builtin_expect_with_probability( !!(exp), true, 0.995 ))
|
|
||||||
# define UTILS_VERY_UNLIKELY( exp ) (__builtin_expect_with_probability( !!(exp), false, 0.995 ))
|
|
||||||
# else
|
|
||||||
# define UTILS_VERY_LIKELY( exp ) (__builtin_expect_with_probability( !!(exp), 1, 0.995 ))
|
|
||||||
# define UTILS_VERY_UNLIKELY( exp ) (__builtin_expect_with_probability( !!(exp), 0, 0.995 ))
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define UTILS_VERY_LIKELY( exp ) (!!(exp))
|
|
||||||
# define UTILS_VERY_UNLIKELY( exp ) (!!(exp))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_builtin(__builtin_prefetch)
|
#if __has_builtin(__builtin_prefetch)
|
||||||
# define UTILS_PREFETCH( exp ) (__builtin_prefetch(exp))
|
# define UTILS_PREFETCH( exp ) (__builtin_prefetch(exp))
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ void panic(const char *func, const char * file, int line, const char *assertion)
|
|||||||
# define assert_invariant(e) ((void)0)
|
# define assert_invariant(e) ((void)0)
|
||||||
#else
|
#else
|
||||||
# define assert_invariant(e) \
|
# define assert_invariant(e) \
|
||||||
(UTILS_VERY_LIKELY(e) ? ((void)0) : utils::panic(__func__, __FILE__, __LINE__, #e))
|
(UTILS_LIKELY(e) ? ((void)0) : utils::panic(__func__, __FILE__, __LINE__, #e))
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
#endif // TNT_UTILS_DEBUG_H
|
#endif // TNT_UTILS_DEBUG_H
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
import os
|
||||||
import glob
|
import glob
|
||||||
import yaml
|
import yaml
|
||||||
@@ -37,14 +36,12 @@ def get_func_name(msg):
|
|||||||
return msg
|
return msg
|
||||||
|
|
||||||
def run_tidy(files):
|
def run_tidy(files):
|
||||||
if len(files) == 0:
|
|
||||||
return []
|
|
||||||
files_str = ' '.join(files)
|
files_str = ' '.join(files)
|
||||||
hid = hashlib.md5(files_str.encode('utf-8')).hexdigest()
|
hid = hashlib.md5(files_str.encode('utf-8')).hexdigest()
|
||||||
_, _ = execute(f'clang-tidy --export-fixes=/tmp/{hid}.yaml --quiet --checks=-*,bugprone-exception-escape {files_str}')
|
_, _ = execute(f'clang-tidy --export-fixes=/tmp/{hid}.yaml --quiet --checks=-*,bugprone-exception-escape {files_str}')
|
||||||
results = []
|
results = []
|
||||||
with open(f'/tmp/{hid}.yaml', 'r') as f:
|
with open(f'/tmp/{hid}.yaml', 'r') as file:
|
||||||
data = yaml.safe_load(f)
|
data = yaml.safe_load(file)
|
||||||
for d in data['Diagnostics']:
|
for d in data['Diagnostics']:
|
||||||
if d['DiagnosticName'] != 'bugprone-exception-escape':
|
if d['DiagnosticName'] != 'bugprone-exception-escape':
|
||||||
continue
|
continue
|
||||||
@@ -55,20 +52,12 @@ def run_tidy(files):
|
|||||||
results.append((msg['FilePath'].replace(f'{os.getcwd()}/', ''), line_num, get_func_name(msg['Message'])))
|
results.append((msg['FilePath'].replace(f'{os.getcwd()}/', ''), line_num, get_func_name(msg['Message'])))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
DEFAULT_SRC_GLOBS=[
|
def exception_escape_test():
|
||||||
'filament/**/*.mm',
|
files = glob.glob('filament/**/*.mm', recursive=True) + \
|
||||||
'filament/**/*.cpp',
|
glob.glob('filament/**/*.cpp', recursive=True) + \
|
||||||
'filament/**/*.h',
|
glob.glob('filament/**/*.h', recursive=True)
|
||||||
]
|
|
||||||
|
|
||||||
def exception_escape_test(src_globs=DEFAULT_SRC_GLOBS):
|
num_workers = 5 # Number of threads to spawn
|
||||||
files = []
|
|
||||||
if not isinstance(src_globs, list):
|
|
||||||
src_globs = [src_globs]
|
|
||||||
for i in src_globs:
|
|
||||||
files += glob.glob(i, recursive=True)
|
|
||||||
|
|
||||||
num_workers = min(len(files), 5) # Number of threads to spawn
|
|
||||||
part_len = len(files) // num_workers
|
part_len = len(files) // num_workers
|
||||||
workloads = []
|
workloads = []
|
||||||
for i in range(num_workers):
|
for i in range(num_workers):
|
||||||
@@ -89,46 +78,21 @@ def exception_escape_test(src_globs=DEFAULT_SRC_GLOBS):
|
|||||||
test_name = 'code-correctness::exception-escape'
|
test_name = 'code-correctness::exception-escape'
|
||||||
failure_str_lines = []
|
failure_str_lines = []
|
||||||
if len(all_results) > 0:
|
if len(all_results) > 0:
|
||||||
all_results.sort(key=lambda x: x[0])
|
|
||||||
failure_str_lines.append(f'Number of failures: {len(all_results)}')
|
failure_str_lines.append(f'Number of failures: {len(all_results)}')
|
||||||
for fname, line_num, msg in all_results:
|
for fname, line_num, msg in all_results:
|
||||||
failure_str_lines.append(f'{fname}({line_num}): {msg}()')
|
failure_str_lines.append(f'{fname}({line_num}): {msg}()')
|
||||||
return (len(all_results) == 0, failure_str_lines)
|
return (len(all_results) == 0, failure_str_lines)
|
||||||
|
|
||||||
TESTS = [
|
TESTS = [
|
||||||
(
|
(exception_escape_test,
|
||||||
exception_escape_test,
|
'exception-escape',
|
||||||
# Test name
|
'\'an exception may be thrown in a function which should not throw exceptions\'')
|
||||||
'exception-escape',
|
|
||||||
|
|
||||||
# Test description
|
|
||||||
'An exception may be thrown in a function which should not throw exceptions. '
|
|
||||||
'Consider adding \'NOLINT(bugprone-exception-escape)\' for valid suppression this check.',
|
|
||||||
|
|
||||||
# Maps a command line argument to a function argument
|
|
||||||
[('exception_escape_globs', 'src_globs')],
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
|
|
||||||
for f, name, desc, args in TESTS:
|
|
||||||
for cmd_arg_name, _ in args:
|
|
||||||
parser.add_argument(f'--{cmd_arg_name}', required=False)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
has_failures = False
|
has_failures = False
|
||||||
for test_func, test_name, test_desc, arguments in TESTS:
|
for test_func, test_name, test_desc in TESTS:
|
||||||
func_args = {}
|
result, res_strs = test_func()
|
||||||
for cmdline_arg, func_arg in arguments:
|
|
||||||
arg_val = getattr(args, cmdline_arg, None)
|
|
||||||
if arg_val is not None:
|
|
||||||
func_args[func_arg] = arg_val.split(',') if ',' in arg_val else arg_val
|
|
||||||
|
|
||||||
result, res_strs = test_func(**func_args)
|
|
||||||
|
|
||||||
ss = ' ' * 4
|
ss = ' ' * 4
|
||||||
if result:
|
if result:
|
||||||
print(f'[{test_name}] PASSED')
|
print(f'[{test_name}] PASSED')
|
||||||
@@ -140,5 +104,6 @@ if __name__ == "__main__":
|
|||||||
print(f'{ss}{s}')
|
print(f'{ss}{s}')
|
||||||
if has_failures:
|
if has_failures:
|
||||||
# TODO: Enable this when we've fixed all the exception-escape errors
|
# TODO: Enable this when we've fixed all the exception-escape errors
|
||||||
#exit(1)
|
#exit(1)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -25,4 +25,4 @@ if ! command -v clang-tidy > /dev/null 2>&1; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
set -e && set -x && \
|
set -e && set -x && \
|
||||||
python3 ${CODE_CORRECTNESS_TEST_DIR}/src/run.py "$@"
|
python3 ${CODE_CORRECTNESS_TEST_DIR}/src/run.py
|
||||||
|
|||||||
Reference in New Issue
Block a user