Skip to content

Commit

Permalink
Merge branch 'main' into dev/transparent-picking-api
Browse files Browse the repository at this point in the history
  • Loading branch information
show50726 authored Oct 22, 2024
2 parents 0b53965 + eab8490 commit ac77bad
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 51 deletions.
2 changes: 2 additions & 0 deletions filament/backend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,8 @@ if (APPLE AND NOT IOS)

add_executable(metal_utils_test test/MetalTest.mm)

target_compile_options(metal_utils_test PRIVATE "-fobjc-arc")

target_link_libraries(metal_utils_test PRIVATE
backend
getopt
Expand Down
13 changes: 12 additions & 1 deletion filament/backend/include/backend/DriverEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,19 @@ struct Viewport {
int32_t right() const noexcept { return left + int32_t(width); }
//! get the top coordinate in window space of the viewport
int32_t top() const noexcept { return bottom + int32_t(height); }
};

friend bool operator==(Viewport const& lhs, Viewport const& rhs) noexcept {
// clang can do this branchless with xor/or
return lhs.left == rhs.left && lhs.bottom == rhs.bottom &&
lhs.width == rhs.width && lhs.height == rhs.height;
}

friend bool operator!=(Viewport const& lhs, Viewport const& rhs) noexcept {
// clang is being dumb and uses branches
return bool(((lhs.left ^ rhs.left) | (lhs.bottom ^ rhs.bottom)) |
((lhs.width ^ rhs.width) | (lhs.height ^ rhs.height)));
}
};

/**
* Specifies the mapping of the near and far clipping plane to window coordinates.
Expand Down
1 change: 1 addition & 0 deletions filament/backend/src/metal/MetalContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ struct MetalContext {
CullModeStateTracker cullModeState;
WindingStateTracker windingState;
DepthClampStateTracker depthClampState;
ScissorRectStateTracker scissorRectState;
Handle<HwRenderPrimitive> currentRenderPrimitive;

// State caches.
Expand Down
7 changes: 6 additions & 1 deletion filament/backend/src/metal/MetalDriver.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,7 @@
mContext->depthStencilState.invalidate();
mContext->cullModeState.invalidate();
mContext->windingState.invalidate();
mContext->scissorRectState.invalidate();
mContext->currentPolygonOffset = {0.0f, 0.0f};

mContext->finalizedDescriptorSets.clear();
Expand Down Expand Up @@ -1953,7 +1954,11 @@
.height = static_cast<NSUInteger>(bottom - top)
};

[mContext->currentRenderPassEncoder setScissorRect:scissorRect];
auto& srs = mContext->scissorRectState;
srs.updateState(scissorRect);
if (srs.stateChanged()) {
[mContext->currentRenderPassEncoder setScissorRect:scissorRect];
}
}

void MetalDriver::beginTimerQuery(Handle<HwTimerQuery> tqh) {
Expand Down
3 changes: 2 additions & 1 deletion filament/backend/src/metal/MetalEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ constexpr inline MTLIndexType getIndexType(size_t elementSize) noexcept {
} else if (elementSize == 4) {
return MTLIndexTypeUInt32;
}
FILAMENT_CHECK_POSTCONDITION(false) << "Index element size not supported.";
assert_invariant(false);
return MTLIndexTypeUInt16;
}

constexpr inline MTLVertexFormat getMetalFormat(ElementType type, bool normalized) noexcept {
Expand Down
18 changes: 13 additions & 5 deletions filament/backend/src/metal/MetalState.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,17 +204,16 @@ class StateCache {
// Different kinds of state, like pipeline state, uniform buffer state, etc., are passed to the
// current Metal command encoder and persist throughout the lifetime of the encoder (a frame).
// StateTracker is used to prevent calling redundant state change methods.
template<typename StateType>
template <typename StateType, typename StateEqual = std::equal_to<StateType>>
class StateTracker {

public:

// Call to force the state to dirty at the beginning of each frame, as all state must be
// re-bound.
void invalidate() noexcept { mStateDirty = true; }

void updateState(const StateType& newState) noexcept {
if (mCurrentState != newState) {
if (!StateEqual()(mCurrentState, newState)) {
mCurrentState = newState;
mStateDirty = true;
}
Expand All @@ -235,7 +234,6 @@ class StateTracker {

bool mStateDirty = true;
StateType mCurrentState = {};

};

// Pipeline state
Expand Down Expand Up @@ -343,6 +341,16 @@ using DepthStencilStateTracker = StateTracker<DepthStencilState>;
using DepthStencilStateCache = StateCache<DepthStencilState, id<MTLDepthStencilState>,
DepthStateCreator>;

struct MtlScissorRectEqual {
bool operator()(const MTLScissorRect& lhs, const MTLScissorRect& rhs) const {
return lhs.height == rhs.height &&
lhs.width == rhs.width &&
lhs.x == rhs.x &&
lhs.y == rhs.y;
}
};
using ScissorRectStateTracker = StateTracker<MTLScissorRect, MtlScissorRectEqual>;

// Uniform buffers

class MetalBufferObject;
Expand Down Expand Up @@ -434,7 +442,7 @@ class MetalBufferBindings {

private:
static_assert(N <= 8);
std::array<__unsafe_unretained id<MTLBuffer>, N> mBuffers = { nil };
std::array<__weak id<MTLBuffer>, N> mBuffers = { nil };
std::array<NSUInteger, N> mOffsets = { 0 };
utils::bitset8 mDirtyBuffers;
utils::bitset8 mDirtyOffsets;
Expand Down
28 changes: 18 additions & 10 deletions filament/backend/src/opengl/platforms/PlatformWGL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
#include <Wingdi.h>

#ifdef _MSC_VER
// this variable is checked in BlueGL.h (included from "gl_headers.h" right after this),
// and prevents duplicate definition of OpenGL apis when building this file.
// this variable is checked in BlueGL.h (included from "gl_headers.h" right after this),
// and prevents duplicate definition of OpenGL apis when building this file.
// However, GL_GLEXT_PROTOTYPES need to be defined in BlueGL.h when included from other files.
#define FILAMENT_PLATFORM_WGL
#endif
Expand All @@ -37,9 +37,8 @@

namespace {

void reportLastWindowsError() {
void reportWindowsError(DWORD dwError) {
LPSTR lpMessageBuffer = nullptr;
DWORD dwError = GetLastError();

if (dwError == 0) {
return;
Expand Down Expand Up @@ -80,6 +79,7 @@ Driver* PlatformWGL::createDriver(void* const sharedGLContext,
const Platform::DriverConfig& driverConfig) noexcept {
int result = 0;
int pixelFormat = 0;
DWORD dwError = 0;

mPfd = {
sizeof(PIXELFORMATDESCRIPTOR),
Expand All @@ -105,6 +105,7 @@ Driver* PlatformWGL::createDriver(void* const sharedGLContext,
mHWnd = CreateWindowA("STATIC", "dummy", 0, 0, 0, 1, 1, NULL, NULL, NULL, NULL);
HDC whdc = mWhdc = GetDC(mHWnd);
if (whdc == NULL) {
dwError = GetLastError();
utils::slog.e << "CreateWindowA() failed" << utils::io::endl;
goto error;
}
Expand All @@ -115,6 +116,7 @@ Driver* PlatformWGL::createDriver(void* const sharedGLContext,
// We need a tmp context to retrieve and call wglCreateContextAttribsARB.
tempContext = wglCreateContext(whdc);
if (!wglMakeCurrent(whdc, tempContext)) {
dwError = GetLastError();
utils::slog.e << "wglMakeCurrent() failed, whdc=" << whdc << ", tempContext=" <<
tempContext << utils::io::endl;
goto error;
Expand All @@ -136,6 +138,7 @@ Driver* PlatformWGL::createDriver(void* const sharedGLContext,
if (mContext) {
break;
}
dwError = GetLastError();
}

if (!mContext) {
Expand All @@ -148,6 +151,7 @@ Driver* PlatformWGL::createDriver(void* const sharedGLContext,
tempContext = NULL;

if (!wglMakeCurrent(whdc, mContext)) {
dwError = GetLastError();
utils::slog.e << "wglMakeCurrent() failed, whdc=" << whdc << ", mContext=" <<
mContext << utils::io::endl;
goto error;
Expand All @@ -162,7 +166,7 @@ Driver* PlatformWGL::createDriver(void* const sharedGLContext,
if (tempContext) {
wglDeleteContext(tempContext);
}
reportLastWindowsError();
reportWindowsError(dwError);
terminate();
return NULL;
}
Expand Down Expand Up @@ -205,9 +209,11 @@ Platform::SwapChain* PlatformWGL::createSwapChain(void* nativeWindow, uint64_t f
// on Windows, the nativeWindow maps to a HWND
swapChain->hWnd = (HWND) nativeWindow;
swapChain->hDc = GetDC(swapChain->hWnd);
if (!ASSERT_POSTCONDITION_NON_FATAL(swapChain->hDc,
"Unable to create the SwapChain (nativeWindow = %p)", nativeWindow)) {
reportLastWindowsError();
if (!swapChain->hDc) {
DWORD dwError = GetLastError();
ASSERT_POSTCONDITION_NON_FATAL(swapChain->hDc,
"Unable to create the SwapChain (nativeWindow = %p)", nativeWindow);
reportWindowsError(dwError);
}

// We have to match pixel formats across the HDC and HGLRC (mContext)
Expand Down Expand Up @@ -264,8 +270,10 @@ bool PlatformWGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
HDC hdc = wglSwapChain->hDc;
if (hdc != NULL) {
BOOL success = wglMakeCurrent(hdc, mContext);
if (!ASSERT_POSTCONDITION_NON_FATAL(success, "wglMakeCurrent() failed. hdc = %p", hdc)) {
reportLastWindowsError();
if (!success) {
DWORD dwError = GetLastError();
ASSERT_POSTCONDITION_NON_FATAL(success, "wglMakeCurrent() failed. hdc = %p", hdc);
reportWindowsError(dwError);
wglMakeCurrent(0, NULL);
}
}
Expand Down
50 changes: 29 additions & 21 deletions filament/src/RenderPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -861,12 +861,6 @@ void RenderPass::Executor::overridePolygonOffset(backend::PolygonOffset const* p
}
}

void RenderPass::Executor::overrideScissor(backend::Viewport const* scissor) noexcept {
if ((mScissorOverride = (scissor != nullptr))) { // NOLINT(*-assignment-in-if-condition)
mScissor = *scissor;
}
}

void RenderPass::Executor::overrideScissor(backend::Viewport const& scissor) noexcept {
mScissorOverride = true;
mScissor = scissor;
Expand All @@ -883,15 +877,15 @@ backend::Viewport RenderPass::Executor::applyScissorViewport(
// clang vectorizes this!
constexpr int32_t maxvali = std::numeric_limits<int32_t>::max();
// compute new left/bottom, assume no overflow
int32_t l = scissor.left + scissorViewport.left;
int32_t b = scissor.bottom + scissorViewport.bottom;
int32_t const l = scissor.left + scissorViewport.left;
int32_t const b = scissor.bottom + scissorViewport.bottom;
// compute right/top without overflowing, scissor.width/height guaranteed
// to convert to int32
int32_t r = (l > maxvali - int32_t(scissor.width)) ? maxvali : l + int32_t(scissor.width);
int32_t t = (b > maxvali - int32_t(scissor.height)) ? maxvali : b + int32_t(scissor.height);
// clip to the viewport
l = std::max(l, scissorViewport.left);
b = std::max(b, scissorViewport.bottom);
assert_invariant(l == std::max(l, scissorViewport.left));
assert_invariant(b == std::max(b, scissorViewport.bottom));
r = std::min(r, scissorViewport.left + int32_t(scissorViewport.width));
t = std::min(t, scissorViewport.bottom + int32_t(scissorViewport.height));
assert_invariant(r >= l && t >= b);
Expand All @@ -913,9 +907,14 @@ void RenderPass::Executor::execute(FEngine& engine,
if (first != last) {
SYSTRACE_VALUE32("commandCount", last - first);

bool const scissorOverride = mScissorOverride;
if (UTILS_UNLIKELY(scissorOverride)) {
// initialize with scissor override
// The scissor rectangle is associated to a render pass, so the tracking can be local.
backend::Viewport currentScissor{ 0, 0, INT32_MAX, INT32_MAX };
bool const hasScissorOverride = mScissorOverride;
bool const hasScissorViewport = mHasScissorViewport;
if (UTILS_UNLIKELY(hasScissorViewport || hasScissorOverride)) {
// we should never have both an override and scissor-viewport
assert_invariant(!hasScissorViewport || !hasScissorOverride);
currentScissor = mScissor;
driver.scissor(mScissor);
}

Expand Down Expand Up @@ -999,17 +998,24 @@ void RenderPass::Executor::execute(FEngine& engine,

if (UTILS_UNLIKELY(mi != info.mi)) {
// this is always taken the first time
mi = info.mi;
assert_invariant(mi);
assert_invariant(info.mi);

mi = info.mi;
ma = mi->getMaterial();

if (UTILS_LIKELY(!scissorOverride)) {
// if we have the scissor override, the material instance and scissor-viewport
// are ignored (typically used for shadow maps).
if (!hasScissorOverride) {
// apply the MaterialInstance scissor
backend::Viewport scissor = mi->getScissor();
if (UTILS_UNLIKELY(mi->hasScissor())) {
scissor = applyScissorViewport(mScissorViewport, scissor);
if (hasScissorViewport) {
// apply the scissor viewport if any
scissor = applyScissorViewport(mScissor, scissor);
}
if (scissor != currentScissor) {
currentScissor = scissor;
driver.scissor(scissor);
}
driver.scissor(scissor);
}

if (UTILS_LIKELY(!polygonOffsetOverride)) {
Expand Down Expand Up @@ -1100,16 +1106,18 @@ RenderPass::Executor::Executor(RenderPass const& pass, Command const* b, Command
mInstancedUboHandle(pass.mInstancedUboHandle),
mInstancedDescriptorSetHandle(pass.mInstancedDescriptorSetHandle),
mColorPassDescriptorSet(pass.mColorPassDescriptorSet),
mScissorViewport(pass.mScissorViewport),
mScissor(pass.mScissorViewport),
mPolygonOffsetOverride(false),
mScissorOverride(false) {
mHasScissorViewport = mScissor != backend::Viewport{ 0, 0, INT32_MAX, INT32_MAX };
assert_invariant(b >= pass.begin());
assert_invariant(e <= pass.end());
}

RenderPass::Executor::Executor() noexcept
: mPolygonOffsetOverride(false),
mScissorOverride(false) {
mScissorOverride(false),
mHasScissorViewport(false) {
}

RenderPass::Executor::Executor(Executor&& rhs) noexcept = default;
Expand Down
25 changes: 15 additions & 10 deletions filament/src/RenderPass.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,12 +350,17 @@ class RenderPass {
BufferObjectSharedHandle mInstancedUboHandle;
DescriptorSetSharedHandle mInstancedDescriptorSetHandle;
ColorPassDescriptorSet const* mColorPassDescriptorSet = nullptr;
backend::Viewport mScissorViewport;

backend::Viewport mScissor{}; // value of scissor override
backend::PolygonOffset mPolygonOffset{}; // value of the override
bool mPolygonOffsetOverride : 1; // whether to override the polygon offset setting
bool mScissorOverride : 1; // whether to override the polygon offset setting
// this stores either the scissor-viewport or the scissor override
backend::Viewport mScissor{ 0, 0, INT32_MAX, INT32_MAX };

// value of the polygon offset override
backend::PolygonOffset mPolygonOffset{};
// whether to override the polygon offset from the MaterialInstance
bool mPolygonOffsetOverride : 1;
// whether to override the scissor rectangle from the MaterialInstance
bool mScissorOverride : 1;
// whether the scissor-viewport is set
bool mHasScissorViewport : 1;

Executor(RenderPass const& pass, Command const* b, Command const* e) noexcept;

Expand All @@ -382,8 +387,6 @@ class RenderPass {
// if non-null, overrides the material's polygon offset
void overridePolygonOffset(backend::PolygonOffset const* polygonOffset) noexcept;

// if non-null, overrides the material's scissor
void overrideScissor(backend::Viewport const* scissor) noexcept;
void overrideScissor(backend::Viewport const& scissor) noexcept;

void execute(FEngine& engine, const char* name) const noexcept;
Expand Down Expand Up @@ -420,7 +423,7 @@ class RenderPass {
uint8_t channel, Pass pass, CustomCommand custom, uint32_t order,
Executor::CustomCommandFn command);

static Command* resize(Arena& arena, Command* const last) noexcept;
static Command* resize(Arena& arena, Command* last) noexcept;

// sorts commands then trims sentinels
static Command* sortCommands(
Expand Down Expand Up @@ -461,7 +464,7 @@ class RenderPass {

FScene::RenderableSoa const& mRenderableSoa;
ColorPassDescriptorSet const* const mColorPassDescriptorSet;
backend::Viewport const mScissorViewport;
backend::Viewport const mScissorViewport{ 0, 0, INT32_MAX, INT32_MAX };
Command const* /* const */ mCommandBegin = nullptr; // Pointer to the first command
Command const* /* const */ mCommandEnd = nullptr; // Pointer to one past the last command
mutable BufferObjectSharedHandle mInstancedUboHandle; // ubo for instanced primitives
Expand Down Expand Up @@ -509,6 +512,8 @@ class RenderPassBuilder {
return *this;
}

// Specifies the viewport for the scissor rectangle, that is, the final scissor rect is
// offset by the viewport's left-top and clipped to the viewport's width/height.
RenderPassBuilder& scissorViewport(backend::Viewport viewport) noexcept {
mScissorViewport = viewport;
return *this;
Expand Down
5 changes: 4 additions & 1 deletion filament/src/components/RenderableManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,10 @@ void FRenderableManager::setMaterialInstanceAt(Instance instance, uint8_t level,
primitives[primitiveIndex].setMaterialInstance(mi);
AttributeBitset const required = material->getRequiredAttributes();
AttributeBitset const declared = primitives[primitiveIndex].getEnabledAttributes();
if (UTILS_UNLIKELY((declared & required) != required)) {
// Print the warning only when the handle is available. Otherwise this may end up
// emitting many invalid warnings as the `declared` bitset is not populated yet.
bool const isPrimitiveInitialized = !!primitives[primitiveIndex].getHwHandle();
if (UTILS_UNLIKELY(isPrimitiveInitialized && (declared & required) != required)) {
slog.w << "[instance=" << instance.asValue() << ", primitive @ " << primitiveIndex
<< "] missing required attributes ("
<< required << "), declared=" << declared << io::endl;
Expand Down
Loading

0 comments on commit ac77bad

Please sign in to comment.