Compare commits
8 Commits
pf/add-fil
...
kpiascik/v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04efb9e18d | ||
|
|
c2c744b06d | ||
|
|
1e246d1332 | ||
|
|
7d242341f2 | ||
|
|
e625c7024c | ||
|
|
192a61a06b | ||
|
|
6a93e3a765 | ||
|
|
e1fb1391f9 |
@@ -495,18 +495,12 @@ struct DescriptorSetLayoutBinding {
|
||||
DescriptorFlags flags = DescriptorFlags::NONE;
|
||||
uint16_t count = 0;
|
||||
|
||||
// TODO: uncomment when needed. Note that this class is used as hash key. We need to ensure
|
||||
// no uninitialized padding bytes.
|
||||
// uint8_t externalSamplerDataIndex = EXTERNAL_SAMPLER_DATA_INDEX_UNUSED;
|
||||
|
||||
friend bool operator==(DescriptorSetLayoutBinding const& lhs,
|
||||
DescriptorSetLayoutBinding const& rhs) noexcept {
|
||||
return lhs.type == rhs.type &&
|
||||
lhs.flags == rhs.flags &&
|
||||
lhs.count == rhs.count &&
|
||||
lhs.stageFlags == rhs.stageFlags;
|
||||
// lhs.stageFlags == rhs.stageFlags &&
|
||||
// lhs.externalSamplerDataIndex == rhs.externalSamplerDataIndex;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1254,26 +1248,6 @@ enum class SamplerCompareFunc : uint8_t {
|
||||
N //!< Never. The depth / stencil test always fails.
|
||||
};
|
||||
|
||||
//! this API is copied from (and only applies to) the Vulkan spec.
|
||||
//! These specify YUV to RGB conversions.
|
||||
enum class SamplerYcbcrModelConversion : uint8_t {
|
||||
RGB_IDENTITY = 0,
|
||||
YCBCR_IDENTITY = 1,
|
||||
YCBCR_709 = 2,
|
||||
YCBCR_601 = 3,
|
||||
YCBCR_2020 = 4,
|
||||
};
|
||||
|
||||
enum class SamplerYcbcrRange : uint8_t {
|
||||
ITU_FULL = 0,
|
||||
ITU_NARROW = 1,
|
||||
};
|
||||
|
||||
enum class ChromaLocation : uint8_t {
|
||||
COSITED_EVEN = 0,
|
||||
MIDPOINT = 1,
|
||||
};
|
||||
|
||||
//! Sampler parameters
|
||||
struct SamplerParams { // NOLINT
|
||||
SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST)
|
||||
@@ -1342,94 +1316,9 @@ static_assert(sizeof(SamplerParams) == 4);
|
||||
static_assert(sizeof(SamplerParams) <= sizeof(uint64_t),
|
||||
"SamplerParams must be no more than 64 bits");
|
||||
|
||||
//! Sampler parameters
|
||||
struct SamplerYcbcrConversion {// NOLINT
|
||||
SamplerYcbcrModelConversion ycbcrModel : 4;
|
||||
TextureSwizzle r : 4;
|
||||
TextureSwizzle g : 4;
|
||||
TextureSwizzle b : 4;
|
||||
TextureSwizzle a : 4;
|
||||
SamplerYcbcrRange ycbcrRange : 1;
|
||||
ChromaLocation xChromaOffset : 1;
|
||||
ChromaLocation yChromaOffset : 1;
|
||||
SamplerMagFilter chromaFilter : 1;
|
||||
uint8_t padding;
|
||||
|
||||
struct Hasher {
|
||||
size_t operator()(const SamplerYcbcrConversion p) const noexcept {
|
||||
// we don't use std::hash<> here, so we don't have to include <functional>
|
||||
return *reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&p));
|
||||
}
|
||||
};
|
||||
|
||||
struct EqualTo {
|
||||
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
|
||||
assert_invariant(lhs.padding == 0);
|
||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||
return *pLhs == *pRhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct LessThan {
|
||||
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
|
||||
assert_invariant(lhs.padding == 0);
|
||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||
return *pLhs < *pRhs;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
friend bool operator == (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
noexcept {
|
||||
return SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
||||
}
|
||||
friend bool operator != (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
noexcept {
|
||||
return !SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
||||
}
|
||||
friend bool operator < (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
noexcept {
|
||||
return SamplerYcbcrConversion::LessThan{}(lhs, rhs);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(SamplerYcbcrConversion) == 4);
|
||||
|
||||
static_assert(sizeof(SamplerYcbcrConversion) <= sizeof(uint64_t),
|
||||
"SamplerYcbcrConversion must be no more than 64 bits");
|
||||
|
||||
struct ExternalSamplerDatum {
|
||||
ExternalSamplerDatum(SamplerYcbcrConversion ycbcr, SamplerParams spm, uint32_t extFmt)
|
||||
: YcbcrConversion(ycbcr),
|
||||
samplerParams(spm),
|
||||
externalFormat(extFmt) {}
|
||||
bool operator==(ExternalSamplerDatum const& rhs) const {
|
||||
return (YcbcrConversion == rhs.YcbcrConversion && samplerParams == rhs.samplerParams &&
|
||||
externalFormat == rhs.externalFormat);
|
||||
}
|
||||
struct EqualTo {
|
||||
bool operator()(const ExternalSamplerDatum& lhs,
|
||||
const ExternalSamplerDatum& rhs) const noexcept {
|
||||
return (lhs.YcbcrConversion == rhs.YcbcrConversion &&
|
||||
lhs.samplerParams == rhs.samplerParams &&
|
||||
lhs.externalFormat == rhs.externalFormat);
|
||||
}
|
||||
};
|
||||
SamplerYcbcrConversion YcbcrConversion;
|
||||
SamplerParams samplerParams;
|
||||
uint32_t externalFormat;
|
||||
};
|
||||
// No implicit padding allowed due to it being a hash key.
|
||||
static_assert(sizeof(ExternalSamplerDatum) == 12);
|
||||
|
||||
struct DescriptorSetLayout {
|
||||
std::variant<utils::StaticString, utils::CString, std::monostate> label;
|
||||
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
||||
|
||||
// TODO: uncomment when needed
|
||||
// utils::FixedCapacityVector<ExternalSamplerDatum> externalSamplerData;
|
||||
};
|
||||
|
||||
//! blending equation function
|
||||
|
||||
@@ -29,6 +29,8 @@ using namespace bluevk;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
using namespace fvkutils;
|
||||
|
||||
VulkanYcbcrConversionCache::VulkanYcbcrConversionCache(VkDevice device)
|
||||
: mDevice(device) {}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_VULKANYCBCRCONVERSIONCACHE_H
|
||||
#define TNT_FILAMENT_BACKEND_VULKANYCBCRCONVERSIONCACHE_H
|
||||
|
||||
#include "utils/Definitions.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/Hash.h>
|
||||
@@ -30,7 +32,7 @@ namespace filament::backend {
|
||||
class VulkanYcbcrConversionCache {
|
||||
public:
|
||||
struct Params {
|
||||
SamplerYcbcrConversion conversion = {}; // 4
|
||||
fvkutils::SamplerYcbcrConversion conversion = {}; // 4
|
||||
VkFormat format; // 4
|
||||
uint64_t externalFormat = 0; // 8
|
||||
};
|
||||
@@ -45,16 +47,15 @@ private:
|
||||
|
||||
struct ConversionEqualTo {
|
||||
bool operator()(Params lhs, Params rhs) const noexcept {
|
||||
SamplerYcbcrConversion::EqualTo equal;
|
||||
fvkutils::SamplerYcbcrConversion::EqualTo equal;
|
||||
return equal(lhs.conversion, rhs.conversion) &&
|
||||
lhs.externalFormat == rhs.externalFormat &&
|
||||
lhs.format == rhs.format;
|
||||
lhs.externalFormat == rhs.externalFormat && lhs.format == rhs.format;
|
||||
}
|
||||
};
|
||||
using ConversionHashFn = utils::hash::MurmurHashFn<Params>;
|
||||
tsl::robin_map<Params, VkSamplerYcbcrConversion, ConversionHashFn, ConversionEqualTo> mCache;
|
||||
};
|
||||
|
||||
}// namespace filament::backend
|
||||
} // namespace filament::backend
|
||||
|
||||
#endif// TNT_FILAMENT_BACKEND_VULKANYCBCRCONVERSIONCACHE_H
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_CONVERSION_H
|
||||
#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_CONVERSION_H
|
||||
|
||||
#include "Definitions.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <private/backend/BackendUtils.h> // for getFormatSize()
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_DEFINITIONS_H
|
||||
#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_DEFINITIONS_H
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
|
||||
@@ -379,6 +381,81 @@ static constexpr uint8_t getFragmentStageShift() noexcept {
|
||||
// We have at most 4 descriptor sets. This is to indicate which ones are active.
|
||||
using DescriptorSetMask = utils::bitset8;
|
||||
|
||||
//! this API is copied from (and only applies to) the Vulkan spec.
|
||||
//! These specify YUV to RGB conversions.
|
||||
enum class SamplerYcbcrModelConversion : uint8_t {
|
||||
RGB_IDENTITY = 0,
|
||||
YCBCR_IDENTITY = 1,
|
||||
YCBCR_709 = 2,
|
||||
YCBCR_601 = 3,
|
||||
YCBCR_2020 = 4,
|
||||
};
|
||||
|
||||
enum class SamplerYcbcrRange : uint8_t {
|
||||
ITU_FULL = 0,
|
||||
ITU_NARROW = 1,
|
||||
};
|
||||
|
||||
enum class ChromaLocation : uint8_t {
|
||||
COSITED_EVEN = 0,
|
||||
MIDPOINT = 1,
|
||||
};
|
||||
|
||||
//! Sampler parameters
|
||||
struct SamplerYcbcrConversion { // NOLINT
|
||||
SamplerYcbcrModelConversion ycbcrModel : 4;
|
||||
TextureSwizzle r : 4;
|
||||
TextureSwizzle g : 4;
|
||||
TextureSwizzle b : 4;
|
||||
TextureSwizzle a : 4;
|
||||
SamplerYcbcrRange ycbcrRange : 1;
|
||||
ChromaLocation xChromaOffset : 1;
|
||||
ChromaLocation yChromaOffset : 1;
|
||||
SamplerMagFilter chromaFilter : 1;
|
||||
uint8_t padding;
|
||||
|
||||
struct Hasher {
|
||||
size_t operator()(const SamplerYcbcrConversion p) const noexcept {
|
||||
// we don't use std::hash<> here, so we don't have to include <functional>
|
||||
return *reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&p));
|
||||
}
|
||||
};
|
||||
|
||||
struct EqualTo {
|
||||
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
|
||||
assert_invariant(lhs.padding == 0);
|
||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||
return *pLhs == *pRhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct LessThan {
|
||||
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
|
||||
assert_invariant(lhs.padding == 0);
|
||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||
return *pLhs < *pRhs;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
friend bool operator==(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) noexcept {
|
||||
return SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
||||
}
|
||||
friend bool operator!=(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) noexcept {
|
||||
return !SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
||||
}
|
||||
friend bool operator<(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) noexcept {
|
||||
return SamplerYcbcrConversion::LessThan{}(lhs, rhs);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(SamplerYcbcrConversion) == 4);
|
||||
|
||||
static_assert(sizeof(SamplerYcbcrConversion) <= sizeof(uint64_t),
|
||||
"SamplerYcbcrConversion must be no more than 64 bits");
|
||||
|
||||
} // namespace filament::backend::fvkutils
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_VULKAN_UTILS_DEFINITIONS_H
|
||||
|
||||
@@ -172,11 +172,15 @@ SPDPipeline& MipmapGenerator::GetOrCreatePipeline(const PipelineCacheKey& key) {
|
||||
entry.binding = i;
|
||||
entry.visibility = wgpu::ShaderStage::Compute;
|
||||
if (i == 0) {
|
||||
entry.texture.sampleType = (key.scalarType == SPDScalarType::I32)
|
||||
? wgpu::TextureSampleType::Sint
|
||||
: (key.scalarType == SPDScalarType::U32)
|
||||
? wgpu::TextureSampleType::Uint
|
||||
: wgpu::TextureSampleType::UnfilterableFloat;
|
||||
if (key.scalarType == SPDScalarType::I32) {
|
||||
entry.texture.sampleType = wgpu::TextureSampleType::Sint;
|
||||
} else if (key.scalarType == SPDScalarType::U32) {
|
||||
entry.texture.sampleType = wgpu::TextureSampleType::Uint;
|
||||
} else if (key.scalarType == SPDScalarType::F32 || key.scalarType == SPDScalarType::F16) {
|
||||
entry.texture.sampleType = wgpu::TextureSampleType::Float;
|
||||
} else {
|
||||
entry.texture.sampleType = wgpu::TextureSampleType::UnfilterableFloat;
|
||||
}
|
||||
entry.texture.viewDimension = wgpu::TextureViewDimension::e2DArray;
|
||||
} else {
|
||||
entry.storageTexture.access = wgpu::StorageTextureAccess::WriteOnly;
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
Driver* WebGPUDriver::create(WebGPUPlatform& platform, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
@@ -335,9 +337,6 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
||||
mDevice, flags);
|
||||
assert_invariant(mSwapChain);
|
||||
|
||||
FWGPU_LOGW << "WebGPU support is highly experimental, in development, and tested for only a "
|
||||
"small set of simple samples (e.g. hellotriangle and texturedquad), thus issues "
|
||||
"are likely to be encountered at this stage.";
|
||||
#if !FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) && !defined(NDEBUG)
|
||||
char printSystemHex[16];
|
||||
snprintf(printSystemHex, sizeof(printSystemHex), "%#x", FWGPU_PRINT_SYSTEM);
|
||||
@@ -606,15 +605,28 @@ uint8_t WebGPUDriver::getMaxDrawBuffers() {
|
||||
}
|
||||
|
||||
size_t WebGPUDriver::getMaxUniformBufferSize() {
|
||||
return 16384u;
|
||||
return mDeviceLimits.maxUniformBufferBindingSize;
|
||||
}
|
||||
|
||||
size_t WebGPUDriver::getMaxTextureSize(const SamplerType target) {
|
||||
return 2048u;
|
||||
size_t result = 2048u;
|
||||
switch (target) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
result = mDeviceLimits.maxTextureDimension2D;
|
||||
break;
|
||||
case SamplerType::SAMPLER_3D:
|
||||
result = mDeviceLimits.maxTextureDimension3D;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t WebGPUDriver::getMaxArrayTextureLayers() {
|
||||
return 256u;
|
||||
return mDeviceLimits.maxTextureArrayLayers;
|
||||
}
|
||||
|
||||
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> indexBufferHandle,
|
||||
@@ -923,6 +935,22 @@ void WebGPUDriver::commit(Handle<HwSwapChain> sch) {
|
||||
assert_invariant(mCommandBuffer);
|
||||
mCommandEncoder = nullptr;
|
||||
mQueue.Submit(1, &mCommandBuffer);
|
||||
|
||||
static bool firstRender = true;
|
||||
// For the first frame rendered, we need to make sure the work is done before presenting or we
|
||||
// get a purple flash
|
||||
if (firstRender) {
|
||||
auto f = mQueue.OnSubmittedWorkDone(wgpu::CallbackMode::WaitAnyOnly,
|
||||
[=](wgpu::QueueWorkDoneStatus) {});
|
||||
const wgpu::Instance instance = mAdapter.GetInstance();
|
||||
auto wStatus = instance.WaitAny(f,
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count());
|
||||
if (wStatus != wgpu::WaitStatus::Success) {
|
||||
FWGPU_LOGW << "Waiting for first frame work to finish resulted in an error"
|
||||
<< static_cast<uint32_t>(wStatus);
|
||||
}
|
||||
firstRender = false;
|
||||
}
|
||||
mCommandBuffer = nullptr;
|
||||
mTextureView = nullptr;
|
||||
assert_invariant(mSwapChain);
|
||||
|
||||
@@ -101,7 +101,7 @@ template<typename WebGPUPrintable>
|
||||
return out.str();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string adapterInfoToString(wgpu::AdapterInfo const& info) {
|
||||
[[nodiscard]] inline std::string adapterInfoToString(wgpu::AdapterInfo const& info) {
|
||||
std::stringstream out;
|
||||
out << "vendor (" << info.vendorID << ") '" << info.vendor
|
||||
<< "' device (" << info.deviceID << ") '" << info.device
|
||||
|
||||
@@ -40,18 +40,24 @@ using namespace filament::math;
|
||||
|
||||
using namespace image;
|
||||
#endif
|
||||
#include <iostream>
|
||||
|
||||
namespace test {
|
||||
|
||||
Backend BackendTest::sBackend = Backend::NOOP;
|
||||
OperatingSystem BackendTest::sOperatingSystem = OperatingSystem::OTHER;
|
||||
bool BackendTest::sIsMobilePlatform = false;
|
||||
int BackendTest::sArgc = 0;
|
||||
char** BackendTest::sArgv = nullptr;
|
||||
std::vector<std::string> BackendTest::sFailedImages;
|
||||
|
||||
void BackendTest::init(Backend backend, OperatingSystem operatingSystem, bool isMobilePlatform) {
|
||||
void BackendTest::init(Backend backend, OperatingSystem operatingSystem, bool isMobilePlatform,
|
||||
int argc, char** argv) {
|
||||
sBackend = backend;
|
||||
sOperatingSystem = operatingSystem;
|
||||
sIsMobilePlatform = isMobilePlatform;
|
||||
sArgc = argc;
|
||||
sArgv = argv;
|
||||
}
|
||||
|
||||
BackendTest::BackendTest() : commandBufferQueue(CONFIG_MIN_COMMAND_BUFFERS_SIZE,
|
||||
@@ -160,6 +166,11 @@ void BackendTest::markImageAsFailure(std::string failedImageName) {
|
||||
sFailedImages.emplace_back(std::move(failedImageName));
|
||||
}
|
||||
|
||||
std::filesystem::path BackendTest::binaryDirectory() {
|
||||
assert(sArgc >= 1);
|
||||
return std::filesystem::path(sArgv[0]).remove_filename().string();
|
||||
}
|
||||
|
||||
void BackendTest::recordFailedImages() {
|
||||
if (!sFailedImages.empty()) {
|
||||
std::string failedImages;
|
||||
@@ -187,8 +198,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void initTests(Backend backend, OperatingSystem operatingSystem, bool isMobile, int& argc, char* argv[]) {
|
||||
BackendTest::init(backend, operatingSystem, isMobile);
|
||||
void initTests(Backend backend, OperatingSystem operatingSystem, bool isMobile, int& argc,
|
||||
char* argv[]) {
|
||||
BackendTest::init(backend, operatingSystem, isMobile, argc, argv);
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
::testing::AddGlobalTestEnvironment(new Environment);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include "private/backend/CommandBufferQueue.h"
|
||||
@@ -31,16 +33,20 @@ namespace test {
|
||||
|
||||
class BackendTest : public ::testing::Test {
|
||||
public:
|
||||
|
||||
static void init(Backend backend, OperatingSystem operatingSystem, bool isMobilePlatform);
|
||||
static void init(Backend backend, OperatingSystem operatingSystem, bool isMobilePlatform,
|
||||
int argc, char** argv);
|
||||
|
||||
static Backend sBackend;
|
||||
static OperatingSystem sOperatingSystem;
|
||||
static bool sIsMobilePlatform;
|
||||
static int sArgc;
|
||||
static char** sArgv;
|
||||
|
||||
// Takes the name of the image that wasn't correct, without the .png suffix
|
||||
static void markImageAsFailure(std::string failedImageName);
|
||||
|
||||
static std::filesystem::path binaryDirectory();
|
||||
|
||||
protected:
|
||||
|
||||
BackendTest();
|
||||
|
||||
@@ -59,28 +59,28 @@ uint32_t ScreenshotParams::expectedHash() const {
|
||||
return mExpectedPixelHash;
|
||||
}
|
||||
|
||||
std::string ScreenshotParams::actualDirectoryPath() {
|
||||
return "images/actual_images";
|
||||
std::filesystem::path ScreenshotParams::actualDirectoryPath() {
|
||||
return BackendTest::binaryDirectory().append("images/actual_images");
|
||||
}
|
||||
|
||||
std::string ScreenshotParams::actualFileName() const {
|
||||
return absl::StrFormat("%s_actual.png", mFileName);
|
||||
}
|
||||
|
||||
std::string ScreenshotParams::actualFilePath() const {
|
||||
return absl::StrFormat("%s/%s", actualDirectoryPath(), actualFileName());
|
||||
std::filesystem::path ScreenshotParams::actualFilePath() const {
|
||||
return actualDirectoryPath().append(actualFileName());
|
||||
}
|
||||
|
||||
std::string ScreenshotParams::expectedDirectoryPath() {
|
||||
return "images/expected_images";
|
||||
std::filesystem::path ScreenshotParams::expectedDirectoryPath() {
|
||||
return BackendTest::binaryDirectory().append("images/expected_images");
|
||||
}
|
||||
|
||||
std::string ScreenshotParams::expectedFileName() const {
|
||||
return absl::StrFormat("%s.png", mFileName);
|
||||
}
|
||||
|
||||
std::string ScreenshotParams::expectedFilePath() const {
|
||||
return absl::StrFormat("%s/%s", expectedDirectoryPath(), expectedFileName());
|
||||
std::filesystem::path ScreenshotParams::expectedFilePath() const {
|
||||
return expectedDirectoryPath().append(expectedFileName());
|
||||
}
|
||||
|
||||
const std::string ScreenshotParams::filePrefix() const {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#ifndef TNT_IMAGE_EXPECTATIONS_H
|
||||
#define TNT_IMAGE_EXPECTATIONS_H
|
||||
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
@@ -51,12 +52,12 @@ public:
|
||||
bool isSrgb() const;
|
||||
uint32_t expectedHash() const;
|
||||
|
||||
static std::string actualDirectoryPath();
|
||||
static std::filesystem::path actualDirectoryPath();
|
||||
std::string actualFileName() const;
|
||||
std::string actualFilePath() const;
|
||||
static std::string expectedDirectoryPath();
|
||||
std::filesystem::path actualFilePath() const;
|
||||
static std::filesystem::path expectedDirectoryPath();
|
||||
std::string expectedFileName() const;
|
||||
std::string expectedFilePath() const;
|
||||
std::filesystem::path expectedFilePath() const;
|
||||
const std::string filePrefix() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -139,6 +139,24 @@ TEST_F(ReadPixelsTest, ReadPixels) {
|
||||
return bufferDimension;
|
||||
}
|
||||
|
||||
void exportScreenshot(void* pixelData) const {
|
||||
#ifndef FILAMENT_IOS
|
||||
const size_t width = readRect.width, height = readRect.height;
|
||||
LinearImage image(width, height, 4);
|
||||
if (format == PixelDataFormat::RGBA && type == PixelDataType::UBYTE) {
|
||||
image = toLinearWithAlpha<uint8_t>(width, height, width * 4, (uint8_t*)pixelData);
|
||||
}
|
||||
if (format == PixelDataFormat::RGBA && type == PixelDataType::FLOAT) {
|
||||
memcpy(image.getPixelRef(), pixelData, width * height * sizeof(math::float4));
|
||||
}
|
||||
std::string png = std::string(testName) + ".png";
|
||||
std::filesystem::path path = ScreenshotParams::actualDirectoryPath();
|
||||
path.append(png);
|
||||
std::ofstream outputStream(path.c_str(), std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::encode(outputStream, ImageEncoder::Format::PNG, image, "", png);
|
||||
#endif
|
||||
}
|
||||
|
||||
// The format and type for the readPixels call.
|
||||
PixelDataFormat format = PixelDataFormat::RGBA;
|
||||
PixelDataType type = PixelDataType::UBYTE;
|
||||
@@ -311,6 +329,8 @@ TEST_F(ReadPixelsTest, ReadPixels) {
|
||||
const auto* test = (const TestCase*)user;
|
||||
assert_invariant(test);
|
||||
|
||||
test->exportScreenshot(buffer);
|
||||
|
||||
// Hash the contents of the buffer and check that they match.
|
||||
uint32_t hash = utils::hash::murmur3((const uint32_t*)buffer, size / 4, 0);
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ DescriptorSet& DescriptorSet::operator=(DescriptorSet&& rhs) noexcept {
|
||||
mDirty = rhs.mDirty;
|
||||
mValid = rhs.mValid;
|
||||
mSetAfterCommitWarning = rhs.mSetAfterCommitWarning;
|
||||
mSetUndefinedParameterWarning = rhs.mSetUndefinedParameterWarning;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -106,11 +107,12 @@ void DescriptorSet::commitSlow(DescriptorSetLayout const& layout,
|
||||
});
|
||||
|
||||
auto const unsetValidDescriptors = layout.getValidDescriptors() & ~mValid;
|
||||
if (UTILS_VERY_UNLIKELY(!unsetValidDescriptors.empty())) {
|
||||
if (UTILS_VERY_UNLIKELY(!unsetValidDescriptors.empty() && !mSetUndefinedParameterWarning)) {
|
||||
unsetValidDescriptors.forEachSetBit([&](auto i) {
|
||||
LOG(WARNING) << (layout.isSampler(i) ? "Sampler" : "Buffer") << " descriptor " << i
|
||||
<< " of " << mName.c_str() << " is not set. Please report this issue.";
|
||||
});
|
||||
mSetUndefinedParameterWarning = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@ private:
|
||||
mutable utils::bitset64 mValid; // 8
|
||||
backend::DescriptorSetHandle mDescriptorSetHandle; // 4
|
||||
mutable bool mSetAfterCommitWarning = false; // 1
|
||||
mutable bool mSetUndefinedParameterWarning = false; // 1
|
||||
utils::StaticString mName; // 16
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user