Compare commits
5 Commits
zm/fix-upd
...
bjd/comman
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2730fbc31b | ||
|
|
7d3b8eb7b9 | ||
|
|
557387375f | ||
|
|
902f869721 | ||
|
|
ad1bc6f360 |
@@ -6,3 +6,5 @@
|
|||||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||||
|
|
||||||
## Release notes for next branch cut
|
## Release notes for next branch cut
|
||||||
|
|
||||||
|
- engine: fix crash when using variance shadow maps
|
||||||
|
|||||||
@@ -578,6 +578,7 @@ if (APPLE OR LINUX)
|
|||||||
test/Shader.cpp
|
test/Shader.cpp
|
||||||
test/SharedShaders.cpp
|
test/SharedShaders.cpp
|
||||||
test/Skip.cpp
|
test/Skip.cpp
|
||||||
|
test/test_Autoresolve.cpp
|
||||||
test/test_FeedbackLoops.cpp
|
test/test_FeedbackLoops.cpp
|
||||||
test/test_Blit.cpp
|
test/test_Blit.cpp
|
||||||
test/test_MissingRequiredAttributes.cpp
|
test/test_MissingRequiredAttributes.cpp
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -64,7 +66,7 @@ public:
|
|||||||
|
|
||||||
// all commands buffers (Slices) written to this point are returned by waitForCommand(). This
|
// all commands buffers (Slices) written to this point are returned by waitForCommand(). This
|
||||||
// call blocks until the CircularBuffer has at least mRequiredSize bytes available.
|
// call blocks until the CircularBuffer has at least mRequiredSize bytes available.
|
||||||
void flush();
|
void flush(std::function<void(void*, void*)> const& debugPrintHistogram = nullptr);
|
||||||
|
|
||||||
// returns from waitForCommands() immediately.
|
// returns from waitForCommands() immediately.
|
||||||
void requestExit();
|
void requestExit();
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ namespace filament::backend {
|
|||||||
|
|
||||||
class CommandBase {
|
class CommandBase {
|
||||||
static constexpr size_t FILAMENT_OBJECT_ALIGNMENT = alignof(std::max_align_t);
|
static constexpr size_t FILAMENT_OBJECT_ALIGNMENT = alignof(std::max_align_t);
|
||||||
|
friend class CommandStream;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using Execute = Dispatcher::Execute;
|
using Execute = Dispatcher::Execute;
|
||||||
@@ -168,8 +169,8 @@ struct CommandType<void (Driver::*)(ARGS...)> {
|
|||||||
|
|
||||||
class CustomCommand : public CommandBase {
|
class CustomCommand : public CommandBase {
|
||||||
std::function<void()> mCommand;
|
std::function<void()> mCommand;
|
||||||
static void execute(Driver&, CommandBase* base, intptr_t* next);
|
|
||||||
public:
|
public:
|
||||||
|
static void execute(Driver&, CommandBase* base, intptr_t* next);
|
||||||
CustomCommand(CustomCommand&& rhs) = default;
|
CustomCommand(CustomCommand&& rhs) = default;
|
||||||
|
|
||||||
explicit CustomCommand(std::function<void()> cmd)
|
explicit CustomCommand(std::function<void()> cmd)
|
||||||
@@ -179,11 +180,12 @@ public:
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
class NoopCommand : public CommandBase {
|
class NoopCommand : public CommandBase {
|
||||||
|
public:
|
||||||
intptr_t mNext;
|
intptr_t mNext;
|
||||||
static void execute(Driver&, CommandBase* self, intptr_t* next) noexcept {
|
static void execute(Driver&, CommandBase* self, intptr_t* next) noexcept {
|
||||||
*next = static_cast<NoopCommand*>(self)->mNext;
|
*next = static_cast<NoopCommand*>(self)->mNext;
|
||||||
}
|
}
|
||||||
public:
|
|
||||||
constexpr explicit NoopCommand(void* next) noexcept
|
constexpr explicit NoopCommand(void* next) noexcept
|
||||||
: CommandBase(execute), mNext(intptr_t((char *)next - (char *)this)) { }
|
: CommandBase(execute), mNext(intptr_t((char *)next - (char *)this)) { }
|
||||||
};
|
};
|
||||||
@@ -219,6 +221,36 @@ public:
|
|||||||
|
|
||||||
CircularBuffer const& getCircularBuffer() const noexcept { return mCurrentBuffer; }
|
CircularBuffer const& getCircularBuffer() const noexcept { return mCurrentBuffer; }
|
||||||
|
|
||||||
|
#if FILAMENT_DEBUG_COMMANDS_HISTOGRAM
|
||||||
|
using Execute = Dispatcher::Execute;
|
||||||
|
struct CommandInfo {
|
||||||
|
size_t size;
|
||||||
|
const char* name;
|
||||||
|
int index;
|
||||||
|
};
|
||||||
|
std::unordered_map<Execute, CommandInfo> mCommands;
|
||||||
|
|
||||||
|
void initializeLookup() {
|
||||||
|
int currentIndex = 0;
|
||||||
|
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params)
|
||||||
|
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
|
||||||
|
mCommands[mDispatcher.methodName##_] = { CommandBase::align(sizeof(COMMAND_TYPE(methodName))), \
|
||||||
|
#methodName, currentIndex++ };
|
||||||
|
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
|
||||||
|
mCommands[mDispatcher.methodName##_] = { \
|
||||||
|
CommandBase::align(sizeof(COMMAND_TYPE(methodName##R))), #methodName, currentIndex++ \
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "private/backend/DriverAPI.inc"
|
||||||
|
|
||||||
|
mCommands[CustomCommand::execute] = { CommandBase::align(sizeof(CustomCommand)),
|
||||||
|
"CustomCommand", currentIndex++ };
|
||||||
|
|
||||||
|
// NoopCommands have variable size. We will handle them specially using their mNext pointer.
|
||||||
|
mCommands[NoopCommand::execute] = { 0, "NoopCommand", currentIndex++ };
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
|
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
|
||||||
inline void methodName(paramsDecl) noexcept { \
|
inline void methodName(paramsDecl) noexcept { \
|
||||||
@@ -263,6 +295,13 @@ public:
|
|||||||
|
|
||||||
void execute(void* buffer);
|
void execute(void* buffer);
|
||||||
|
|
||||||
|
#if FILAMENT_DEBUG_COMMANDS_HISTOGRAM
|
||||||
|
void debugIterateCommands(void* head, void* tail,
|
||||||
|
std::function<void(CommandInfo const& info)> const& callback);
|
||||||
|
|
||||||
|
void debugPrintHistogram(void* head, void* tail);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* queueCommand() allows to queue a lambda function as a command.
|
* queueCommand() allows to queue a lambda function as a command.
|
||||||
* This is much less efficient than using the Driver* API.
|
* This is much less efficient than using the Driver* API.
|
||||||
|
|||||||
@@ -48,6 +48,11 @@
|
|||||||
|
|
||||||
#define FILAMENT_DEBUG_COMMANDS FILAMENT_DEBUG_COMMANDS_NONE
|
#define FILAMENT_DEBUG_COMMANDS FILAMENT_DEBUG_COMMANDS_NONE
|
||||||
|
|
||||||
|
// Upon command stream overflow, print a histogram of commands
|
||||||
|
#ifndef FILAMENT_DEBUG_COMMANDS_HISTOGRAM
|
||||||
|
#define FILAMENT_DEBUG_COMMANDS_HISTOGRAM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
class BufferDescriptor;
|
class BufferDescriptor;
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ bool CommandBufferQueue::isExitRequested() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CommandBufferQueue::flush() {
|
void CommandBufferQueue::flush(std::function<void(void*, void*)> const& debugPrintHistogram) {
|
||||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
|
|
||||||
CircularBuffer& circularBuffer = mCircularBuffer;
|
CircularBuffer& circularBuffer = mCircularBuffer;
|
||||||
@@ -106,6 +106,13 @@ void CommandBufferQueue::flush() {
|
|||||||
std::unique_lock lock(mLock);
|
std::unique_lock lock(mLock);
|
||||||
|
|
||||||
// circular buffer is too small, we corrupted the stream
|
// circular buffer is too small, we corrupted the stream
|
||||||
|
#if FILAMENT_DEBUG_COMMANDS_HISTOGRAM
|
||||||
|
if (UTILS_VERY_UNLIKELY(used > mFreeSpace)) {
|
||||||
|
if (debugPrintHistogram) {
|
||||||
|
debugPrintHistogram(begin, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
FILAMENT_CHECK_POSTCONDITION(used <= mFreeSpace) <<
|
FILAMENT_CHECK_POSTCONDITION(used <= mFreeSpace) <<
|
||||||
"Backend CommandStream overflow. Commands are corrupted and unrecoverable.\n"
|
"Backend CommandStream overflow. Commands are corrupted and unrecoverable.\n"
|
||||||
"Please increase minCommandBufferSizeMB inside the Config passed to Engine::create.\n"
|
"Please increase minCommandBufferSizeMB inside the Config passed to Engine::create.\n"
|
||||||
|
|||||||
@@ -30,6 +30,11 @@
|
|||||||
#include <utils/ostream.h>
|
#include <utils/ostream.h>
|
||||||
#include <utils/sstream.h>
|
#include <utils/sstream.h>
|
||||||
|
|
||||||
|
#if FILAMENT_DEBUG_COMMANDS_HISTOGRAM
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -83,6 +88,10 @@ CommandStream::CommandStream(Driver& driver, CircularBuffer& buffer) noexcept
|
|||||||
__system_property_get("debug.filament.perfcounters", property);
|
__system_property_get("debug.filament.perfcounters", property);
|
||||||
mUsePerformanceCounter = bool(atoi(property));
|
mUsePerformanceCounter = bool(atoi(property));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if FILAMENT_DEBUG_COMMANDS_HISTOGRAM
|
||||||
|
initializeLookup();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandStream::execute(void* buffer) {
|
void CommandStream::execute(void* buffer) {
|
||||||
@@ -126,6 +135,71 @@ void CommandStream::execute(void* buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FILAMENT_DEBUG_COMMANDS_HISTOGRAM
|
||||||
|
void CommandStream::debugIterateCommands(void* head, void* tail,
|
||||||
|
std::function<void(CommandInfo const& info)> const& callback) {
|
||||||
|
CommandBase* UTILS_RESTRICT base = static_cast<CommandBase*>(head);
|
||||||
|
auto p = base;
|
||||||
|
while (UTILS_LIKELY(p)) {
|
||||||
|
if (p >= tail) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Execute e = p->mExecute;
|
||||||
|
|
||||||
|
if (e == NoopCommand::execute) {
|
||||||
|
NoopCommand* noop = static_cast<NoopCommand*>(p);
|
||||||
|
size_t size = noop->mNext;
|
||||||
|
int noopIndex = mCommands[NoopCommand::execute].index;
|
||||||
|
callback({ size, "NoopCommand", noopIndex });
|
||||||
|
p = reinterpret_cast<CommandBase*>(reinterpret_cast<char*>(p) + size);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto it = mCommands.find(e); it != mCommands.end()) {
|
||||||
|
size_t size = it->second.size;
|
||||||
|
callback(it->second);
|
||||||
|
p = reinterpret_cast<CommandBase*>(reinterpret_cast<char*>(p) + size);
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "Cannot find command in lookup table";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandStream::debugPrintHistogram(void* head, void* tail) {
|
||||||
|
std::unordered_map<std::string_view, int> histogram;
|
||||||
|
std::unordered_map<int, int> index_histogram;
|
||||||
|
debugIterateCommands(head, tail, [&](CommandInfo const& info) {
|
||||||
|
histogram[std::string_view(info.name)]++;
|
||||||
|
index_histogram[info.index]++;
|
||||||
|
});
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string_view, int>> sorted_histogram(histogram.begin(),
|
||||||
|
histogram.end());
|
||||||
|
std::sort(sorted_histogram.begin(), sorted_histogram.end(),
|
||||||
|
[](auto const& a, auto const& b) { return a.second > b.second; });
|
||||||
|
|
||||||
|
LOG(INFO) << "Command stream histogram:";
|
||||||
|
for (auto const& [name, count]: sorted_histogram) {
|
||||||
|
LOG(INFO) << name << ": " << count;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<int, int>> sorted_index_histogram(index_histogram.begin(),
|
||||||
|
index_histogram.end());
|
||||||
|
std::sort(sorted_index_histogram.begin(), sorted_index_histogram.end(),
|
||||||
|
[](auto const& a, auto const& b) { return a.second > b.second; });
|
||||||
|
|
||||||
|
std::string short_histogram = "";
|
||||||
|
for (size_t i = 0, n = sorted_index_histogram.size(); i < n; ++i) {
|
||||||
|
short_histogram += std::to_string(sorted_index_histogram[i].first) + ":" +
|
||||||
|
std::to_string(sorted_index_histogram[i].second);
|
||||||
|
short_histogram += (i < n - 1) ? ";" : ".";
|
||||||
|
}
|
||||||
|
LOG(INFO) << "CS hist: " << short_histogram;
|
||||||
|
LOG(INFO) << "";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void CommandStream::queueCommand(std::function<void()> command) {
|
void CommandStream::queueCommand(std::function<void()> command) {
|
||||||
new(allocateCommand(CustomCommand::align(sizeof(CustomCommand)))) CustomCommand(std::move(command));
|
new(allocateCommand(CustomCommand::align(sizeof(CustomCommand)))) CustomCommand(std::move(command));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1092,7 +1092,7 @@ MetalRenderTarget::MetalRenderTarget(MetalContext* context, uint32_t width, uint
|
|||||||
// a multisampled sidecar texture and do a resolve automatically.
|
// a multisampled sidecar texture and do a resolve automatically.
|
||||||
if (samples > 1 && texture->samples == 1) {
|
if (samples > 1 && texture->samples == 1) {
|
||||||
auto& sidecar = texture->msaaSidecar;
|
auto& sidecar = texture->msaaSidecar;
|
||||||
if (!sidecar) {
|
if (!sidecar || sidecar.sampleCount != samples) {
|
||||||
sidecar = createMultisampledTexture(mtlTexture.pixelFormat, texture->width,
|
sidecar = createMultisampledTexture(mtlTexture.pixelFormat, texture->width,
|
||||||
texture->height, samples);
|
texture->height, samples);
|
||||||
}
|
}
|
||||||
@@ -1123,7 +1123,7 @@ MetalRenderTarget::MetalRenderTarget(MetalContext* context, uint32_t width, uint
|
|||||||
// a multisampled sidecar texture and do a resolve automatically.
|
// a multisampled sidecar texture and do a resolve automatically.
|
||||||
if (samples > 1 && texture->samples == 1) {
|
if (samples > 1 && texture->samples == 1) {
|
||||||
auto& sidecar = texture->msaaSidecar;
|
auto& sidecar = texture->msaaSidecar;
|
||||||
if (!sidecar) {
|
if (!sidecar || sidecar.sampleCount != samples) {
|
||||||
sidecar = createMultisampledTexture(mtlTexture.pixelFormat, texture->width,
|
sidecar = createMultisampledTexture(mtlTexture.pixelFormat, texture->width,
|
||||||
texture->height, samples);
|
texture->height, samples);
|
||||||
}
|
}
|
||||||
@@ -1155,7 +1155,7 @@ MetalRenderTarget::MetalRenderTarget(MetalContext* context, uint32_t width, uint
|
|||||||
// a multisampled sidecar texture and do a resolve automatically.
|
// a multisampled sidecar texture and do a resolve automatically.
|
||||||
if (samples > 1 && texture->samples == 1) {
|
if (samples > 1 && texture->samples == 1) {
|
||||||
auto& sidecar = texture->msaaSidecar;
|
auto& sidecar = texture->msaaSidecar;
|
||||||
if (!sidecar) {
|
if (!sidecar || sidecar.sampleCount != samples) {
|
||||||
sidecar = createMultisampledTexture(mtlTexture.pixelFormat, texture->width,
|
sidecar = createMultisampledTexture(mtlTexture.pixelFormat, texture->width,
|
||||||
texture->height, samples);
|
texture->height, samples);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -639,8 +639,8 @@ private:
|
|||||||
template <typename T, typename F>
|
template <typename T, typename F>
|
||||||
static inline void update_state(T& state, T const& expected, F functor, bool force = false) noexcept {
|
static inline void update_state(T& state, T const& expected, F functor, bool force = false) noexcept {
|
||||||
if (UTILS_UNLIKELY(force || state != expected)) {
|
if (UTILS_UNLIKELY(force || state != expected)) {
|
||||||
functor();
|
|
||||||
state = expected;
|
state = expected;
|
||||||
|
functor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
116
filament/backend/test/test_Autoresolve.cpp
Normal file
116
filament/backend/test/test_Autoresolve.cpp
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* 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 "BackendTest.h"
|
||||||
|
|
||||||
|
#include "Shader.h"
|
||||||
|
#include "SharedShaders.h"
|
||||||
|
#include "TrianglePrimitive.h"
|
||||||
|
|
||||||
|
#include <backend/PixelBufferDescriptor.h>
|
||||||
|
|
||||||
|
#include <utils/FixedCapacityVector.h>
|
||||||
|
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
using namespace filament;
|
||||||
|
using namespace filament::backend;
|
||||||
|
using namespace filament::math;
|
||||||
|
|
||||||
|
TEST_F(BackendTest, AutoresolveDifferingSampleCounts) {
|
||||||
|
auto& api = getDriverApi();
|
||||||
|
constexpr int kRenderTargetSize = 512;
|
||||||
|
|
||||||
|
auto swapChain = addCleanup(createSwapChain());
|
||||||
|
api.makeCurrent(swapChain, swapChain);
|
||||||
|
|
||||||
|
Shader shader = SharedShaders::makeShader(api, *mCleanup,
|
||||||
|
{
|
||||||
|
.mVertexType = VertexShaderType::Simple,
|
||||||
|
.mFragmentType = FragmentShaderType::SolidColored,
|
||||||
|
.mUniformType = ShaderUniformType::Simple,
|
||||||
|
});
|
||||||
|
|
||||||
|
TrianglePrimitive triangle(api);
|
||||||
|
PipelineState ps = getColorWritePipelineState();
|
||||||
|
shader.addProgramToPipelineState(ps);
|
||||||
|
|
||||||
|
auto ubuffer = addCleanup(api.createBufferObject(sizeof(SimpleMaterialParams),
|
||||||
|
BufferObjectBinding::UNIFORM, BufferUsage::STATIC));
|
||||||
|
shader.bindUniform<SimpleMaterialParams>(api, ubuffer);
|
||||||
|
|
||||||
|
// Create a texture with sample count = 1.
|
||||||
|
Handle<HwTexture> texture = addCleanup(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||||
|
TextureFormat::RGBA8, 1, kRenderTargetSize, kRenderTargetSize, 1,
|
||||||
|
TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE));
|
||||||
|
|
||||||
|
// First render pass: render a red triangle to a RenderTarget with 8 samples.
|
||||||
|
{
|
||||||
|
Handle<HwRenderTarget> renderTarget =
|
||||||
|
addCleanup(api.createRenderTarget(TargetBufferFlags::COLOR, kRenderTargetSize,
|
||||||
|
kRenderTargetSize, 8, 1, { { texture } }, {}, {}));
|
||||||
|
|
||||||
|
shader.uploadUniform(api, ubuffer,
|
||||||
|
SimpleMaterialParams{
|
||||||
|
.color = float4(1, 0, 0, 1),
|
||||||
|
});
|
||||||
|
|
||||||
|
RenderPassParams params = getClearColorRenderPass(float4(0));
|
||||||
|
params.viewport = { 0, 0, kRenderTargetSize, kRenderTargetSize };
|
||||||
|
|
||||||
|
RenderFrame frame(api);
|
||||||
|
api.beginRenderPass(renderTarget, params);
|
||||||
|
ps.primitiveType = PrimitiveType::TRIANGLES;
|
||||||
|
ps.vertexBufferInfo = triangle.getVertexBufferInfo();
|
||||||
|
api.bindPipeline(ps);
|
||||||
|
api.bindRenderPrimitive(triangle.getRenderPrimitive());
|
||||||
|
api.draw2(0, 3, 1);
|
||||||
|
api.endRenderPass();
|
||||||
|
api.commit(swapChain);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second render pass: render a green triangle to a RenderTarget with 4 samples, attached to
|
||||||
|
// the same texture.
|
||||||
|
{
|
||||||
|
Handle<HwRenderTarget> renderTarget =
|
||||||
|
addCleanup(api.createRenderTarget(TargetBufferFlags::COLOR, kRenderTargetSize,
|
||||||
|
kRenderTargetSize, 4, 1, { { texture } }, {}, {}));
|
||||||
|
|
||||||
|
shader.uploadUniform(api, ubuffer,
|
||||||
|
SimpleMaterialParams{
|
||||||
|
.color = float4(0, 1, 0, 1),
|
||||||
|
});
|
||||||
|
|
||||||
|
RenderPassParams params = getClearColorRenderPass(float4(0));
|
||||||
|
params.viewport = { 0, 0, kRenderTargetSize, kRenderTargetSize };
|
||||||
|
|
||||||
|
RenderFrame frame(api);
|
||||||
|
api.beginRenderPass(renderTarget, params);
|
||||||
|
ps.primitiveType = PrimitiveType::TRIANGLES;
|
||||||
|
ps.vertexBufferInfo = triangle.getVertexBufferInfo();
|
||||||
|
api.bindPipeline(ps);
|
||||||
|
api.bindRenderPrimitive(triangle.getRenderPrimitive());
|
||||||
|
api.draw2(0, 3, 1);
|
||||||
|
api.endRenderPass();
|
||||||
|
|
||||||
|
EXPECT_IMAGE(renderTarget, ScreenshotParams(kRenderTargetSize, kRenderTargetSize,
|
||||||
|
"AutoresolveDifferingSampleCounts", 1048576));
|
||||||
|
|
||||||
|
api.commit(swapChain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
@@ -920,7 +920,12 @@ int FEngine::loop() {
|
|||||||
|
|
||||||
void FEngine::flushCommandBuffer(CommandBufferQueue& commandBufferQueue) const {
|
void FEngine::flushCommandBuffer(CommandBufferQueue& commandBufferQueue) const {
|
||||||
getDriver().purge();
|
getDriver().purge();
|
||||||
commandBufferQueue.flush();
|
commandBufferQueue.flush([this](void* begin, void* end) {
|
||||||
|
UTILS_UNUSED FEngine* engine = const_cast<FEngine*>(this);
|
||||||
|
#if FILAMENT_DEBUG_COMMANDS_HISTOGRAM
|
||||||
|
engine->getDriverApi().debugPrintHistogram(begin, end);
|
||||||
|
#endif
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const FMaterial* FEngine::getSkyboxMaterial() const noexcept {
|
const FMaterial* FEngine::getSkyboxMaterial() const noexcept {
|
||||||
|
|||||||
@@ -378,8 +378,14 @@ private:
|
|||||||
Variant variant = {}) const noexcept;
|
Variant variant = {}) const noexcept;
|
||||||
|
|
||||||
bool isSharedVariant(Variant const variant) const {
|
bool isSharedVariant(Variant const variant) const {
|
||||||
return (mDefinition.materialDomain == MaterialDomain::SURFACE) && !mIsDefaultMaterial &&
|
// HACK: The default material "should" have VSM | DEP, but then we'd have to compile it as a
|
||||||
!mDefinition.hasCustomDepthShader && Variant::isValidDepthVariant(variant);
|
// lit material, which would increase binary size. Perhaps we could specially compile it
|
||||||
|
// with this variant, but with the shader program cache in active development, the days of
|
||||||
|
// the default material are numbered anyway.
|
||||||
|
constexpr Variant::type_t vsmAndDep = Variant::VSM | Variant::DEP;
|
||||||
|
return mDefinition.materialDomain == MaterialDomain::SURFACE && !mIsDefaultMaterial &&
|
||||||
|
!mDefinition.hasCustomDepthShader && Variant::isValidDepthVariant(variant) &&
|
||||||
|
(variant.key & vsmAndDep) != vsmAndDep;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutable utils::FixedCapacityVector<backend::Handle<backend::HwProgram>> mCachedPrograms;
|
mutable utils::FixedCapacityVector<backend::Handle<backend::HwProgram>> mCachedPrograms;
|
||||||
|
|||||||
Reference in New Issue
Block a user