did not plan on actually implementing tr_polys with forward+ (it didn't even solve the issue of incadescent light panels not working right because they're baked into worldspawn)

This commit is contained in:
ecker 2026-06-11 00:08:31 -05:00
parent 590eee0684
commit 595e986903
17 changed files with 365 additions and 99 deletions

View File

@ -87,7 +87,7 @@
]
},
"framebuffer": {
"msaa": 8,
"msaa": 2,
"size": 1
// "size": [ 640, 480, "NEAREST" ]
// "size": [ 1280, 720 ]

View File

@ -1,7 +1,7 @@
{
// "import": "./rp_downtown_v2.json"
// "import": "./ss2_medsci1.json"
"import": "./mds_mcdonalds.json"
// "import": "./cs_office.json"
// "import": "./mds_mcdonalds.json"
"import": "./cs_office.json"
// "import": "./gm_construct.json"
}

View File

@ -0,0 +1,191 @@
#version 450
#pragma shader_stage(fragment)
#define FORWARD 0
#define FRAGMENT 1
#define PBR 1
layout (constant_id = 0) const uint TEXTURES = 1;
layout (constant_id = 1) const uint CUBEMAPS = 128;
#include "../../common/macros.h"
#include "../../common/structs.h"
layout (binding = 6, set = 1) uniform sampler2D samplerTextures[TEXTURES];
layout (binding = 7, set = 1) uniform samplerCube samplerCubemaps[CUBEMAPS];
layout (binding = 8, set = 0) uniform sampler3D samplerNoise;
#if VXGI
layout (binding = 9, set = 0) uniform sampler3D voxelOutput[CASCADES];
#endif
#if RT
layout (binding = 10, set = 0) uniform accelerationStructureEXT tlas;
#endif
layout (std140, binding = 11, set = 0) readonly buffer DrawCommands { DrawCommand drawCommands[]; };
layout (std140, binding = 12, set = 0) readonly buffer Instances { Instance instances[]; };
layout (std140, binding = 13, set = 0) readonly buffer InstanceAddresseses { InstanceAddresses addresses[]; };
layout (std140, binding = 14, set = 0) readonly buffer Materials { Material materials[]; };
layout (std140, binding = 15, set = 0) readonly buffer Textures { Texture textures[]; };
layout (std140, binding = 16, set = 0) readonly buffer Lights { Light lights[]; };
layout (std140, binding = 17, set = 0) readonly buffer Objects { Object objects[]; };
layout (binding = 18) uniform Camera { Viewport viewport[2]; } camera;
// to-do: bind UBO for settings?
/*
layout (binding = 19) uniform UBO { EyeMatrices eyes[2]; Settings settings; } ubo;
*/
#include "../../common/functions.h"
//#include "../../common/light.h"
//#include "../../common/shadows.h"
layout (location = 0) flat in uvec4 inId;
layout (location = 1) flat in vec4 inPOS0;
layout (location = 2) in vec4 inPOS1;
layout (location = 3) in vec3 inPosition;
layout (location = 4) sample in vec2 inUv;
layout (location = 5) in vec4 inColor;
layout (location = 6) in vec2 inSt;
layout (location = 7) in vec3 inNormal;
layout (location = 8) in vec3 inTangent;
layout (location = 0) out vec4 outFragColor;
void main() {
const uint triangleID = gl_PrimitiveID;
const uint drawID = uint(inId.y);
const uint instanceID = uint(inId.z);
#if 0
#if CAN_DISCARD
const DrawCommand drawCommand = drawCommands[drawID];
const Instance instance = instances[instanceID];
const Material material = materials[instance.materialID];
surface.uv.xy = wrap(inUv.xy);
surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv));
surface.st.xy = wrap(inSt.xy);
surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt));
vec4 A = inColor * material.colorBase;
// sample albedo
if ( validTextureIndex( material.indexAlbedo ) ) {
A = sampleTexture( material.indexAlbedo );
}
if ( A.a < 0.0001 ) discard;
#endif
outFragColor.rgb = A.rgb;
outFragColor.a = A.a;
#else
const DrawCommand drawCommand = drawCommands[drawID];
surface.instance = instances[instanceID];
surface.object = objects[surface.instance.objectID];
const Material material = materials[surface.instance.materialID];
surface.uv.xy = wrap(inUv.xy);
surface.st.xy = wrap(inSt.xy);
surface.dUvDx = dFdx(inUv);
surface.dUvDy = dFdy(inUv);
surface.dStDx = dFdx(inSt);
surface.dStDy = dFdy(inSt);
surface.uv.z = mipLevel(surface.dUvDx, surface.dUvDy);
surface.st.z = mipLevel(surface.dStDx, surface.dStDy);
surface.position.world = inPosition;
surface.position.eye = vec3( inverse( surface.object.model ) * vec4(surface.position.world, 1.0) );
surface.normal.world = normalize(inNormal);
surface.tangent.world = normalize(inTangent);
vec3 bitangent = cross(surface.normal.world, surface.tangent.world);
surface.tbn = mat3(surface.tangent.world, bitangent, surface.normal.world);
//
surface.material.albedo = material.colorBase;
surface.material.metallic = material.factorMetallic;
surface.material.roughness = material.factorRoughness;
surface.material.occlusion = material.factorOcclusion;
surface.material.lightmapped = false;
surface.light = material.colorEmissive;
if ( validTextureIndex( material.indexAlbedo ) ) {
surface.material.albedo *= sampleTexture( material.indexAlbedo );
}
// OPAQUE
if ( material.modeAlpha == 0 ) {
surface.material.albedo.a = 1;
// BLEND
} else if ( material.modeAlpha == 1 ) {
// MASK
} else if ( material.modeAlpha == 2 ) {
// EMISSIVE
} else if ( material.modeAlpha == 3 ) {
surface.light.rgb *= surface.material.albedo.rgb * surface.material.albedo.a;
surface.material.albedo.a = 1.0;
}
// Emissive mapping
if ( validTextureIndex( material.indexEmissive ) ) {
surface.light *= sampleTexture( material.indexEmissive );
}
// (Occlusion/)Metallic/Roughness map
if ( validTextureIndex( material.indexMetallicRoughness ) ) {
vec4 samp = sampleTexture( material.indexMetallicRoughness );
surface.material.metallic *= samp.b;
surface.material.roughness *= samp.g;
if ( material.indexOcclusion == material.indexMetallicRoughness ) {
surface.material.occlusion = mix(1.0, samp.r, material.factorOcclusion);
}
}
// Occlusion mapping
if ( validTextureIndex( material.indexOcclusion ) && material.indexOcclusion != material.indexMetallicRoughness ) {
float occ = sampleTexture( material.indexOcclusion ).r;
surface.material.occlusion = mix(1.0, occ, material.factorOcclusion);
}
// Normal mapping
if ( validTextureIndex( material.indexNormal ) && surface.tangent.world != vec3(0) ) {
surface.normal.world = surface.tbn * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - vec3(1.0));
}
{
surface.normal.eye = normalize(vec3( inverse( surface.object.model ) * vec4(surface.normal.world, 0.0) ));
}
// Light mapping
if ( /*( bool(ubo.settings.lighting.useLightmaps)) &&*/ validTextureIndex( surface.instance.lightmapID ) ) {
surface.material.lightmapped = true; // light.a > 0.001;
vec4 light = decodeRGBE( sampleTexture( surface.instance.lightmapID, surface.st.xy, 0.0 ) );
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
const vec3 Lo = normalize(-surface.position.eye);
const float cosLo = max(0.0, dot(surface.normal.eye, Lo));
const vec3 F = F0 + (max(vec3(1.0 - surface.material.roughness), F0) - F0) * pow(clamp(1.0 - cosLo, 0.0, 1.0), 5.0);
const vec3 kD = (vec3(1.0) - F) * (1.0 - surface.material.metallic);
surface.light.rgb += (kD * surface.material.albedo.rgb * light.rgb) * surface.material.occlusion;
}
if ( surface.material.albedo.a < 0.0001 && dot(surface.light.rgb, vec3(1.0)) < 0.0001 ) discard;
surface.fragment = vec4(0.0);
surface.light.rgb += surface.material.albedo.rgb /* ubo.settings.lighting.ambient.rgb*/ * surface.material.occlusion;
/*
#if PBR
pbr();
#elif LAMBERT
lambert();
#endif
*/
outFragColor.rgb = surface.fragment.rgb + surface.light.rgb;
outFragColor.a = surface.material.albedo.a;
#endif
}

View File

@ -174,7 +174,7 @@ vec3 decodeSrgb(vec3 rgb) {
const vec3 c = step(vec3(0.04045), rgb);
return mix(a, b, c);
}
#if !SPD && (DEFERRED || FRAGMENT || COMPUTE || RT)
#if !SPD && (DEFERRED || FRAGMENT || COMPUTE || RT || FORWARD)
bool validTextureIndex( int textureIndex ) {
return 0 <= textureIndex && textureIndex < MAX_TEXTURES;
}
@ -304,6 +304,10 @@ void populateSurfaceMaterial() {
// MASK
} else if ( material.modeAlpha == 2 ) {
// EMISSIVE
} else if ( material.modeAlpha == 3 ) {
surface.light.rgb *= surface.material.albedo.rgb * surface.material.albedo.a;
surface.material.albedo.a = 1.0;
}
// Emissive mapping
@ -348,7 +352,8 @@ void populateSurfaceMaterial() {
surface.light.rgb += (kD * surface.material.albedo.rgb * light.rgb) * surface.material.occlusion;
}
}
#endif
#if DEFERRED_SAMPLING
bool isValidAddress( uint64_t address ) {
#if UINT64_ENABLED
return bool(address);

View File

@ -177,6 +177,8 @@ struct Surface {
vec2 motion;
vec2 dUvDx;
vec2 dUvDy;
vec2 dStDx;
vec2 dStDy;
Ray ray;
@ -192,6 +194,7 @@ struct Surface {
#if MULTISAMPLING
struct MSAA {
int currentID;
float depth;
uvec2 IDs[MAX_MSAA_SAMPLES];
vec4 fragment;
vec4 fragments[MAX_MSAA_SAMPLES];

View File

@ -53,6 +53,9 @@ layout (constant_id = 1) const uint CUBEMAPS = 128;
layout(binding = 7, set = 0, rgba16f) uniform writeonly image2DArray imageColor;
layout(binding = 8, set = 0, rgba16f) uniform writeonly image2DArray imageBright;
layout(binding = 9, set = 0, rg16f) uniform writeonly image2DArray imageMotion;
#if MULTISAMPLING
layout(binding = 10, set = 0, r32f) uniform writeonly image2DArray imageDepthResolved;
#endif
layout( push_constant ) uniform PushBlock {
uint pass;
@ -61,46 +64,46 @@ layout( push_constant ) uniform PushBlock {
#include "../../../common/structs.h"
layout (binding = 10, set = 0) uniform Camera {
layout (binding = 11, set = 0) uniform Camera {
Viewport viewport[2];
} camera;
layout (binding = 11, set = 0) uniform UBO {
layout (binding = 12, set = 0) uniform UBO {
EyeMatrices eyes[2];
Settings settings;
} ubo;
layout (std140, binding = 12, set = 0) readonly buffer DrawCommands {
layout (std140, binding = 13, set = 0) readonly buffer DrawCommands {
DrawCommand drawCommands[];
};
layout (std140, binding = 13, set = 0) readonly buffer Instances {
layout (std140, binding = 14, set = 0) readonly buffer Instances {
Instance instances[];
};
layout (std140, binding = 14, set = 0) readonly buffer InstanceAddresseses {
layout (std140, binding = 15, set = 0) readonly buffer InstanceAddresseses {
InstanceAddresses addresses[];
};
layout (std140, binding = 15, set = 0) readonly buffer Objects {
layout (std140, binding = 16, set = 0) readonly buffer Objects {
Object objects[];
};
layout (std140, binding = 16, set = 0) readonly buffer Materials {
layout (std140, binding = 17, set = 0) readonly buffer Materials {
Material materials[];
};
layout (std140, binding = 17, set = 0) readonly buffer Textures {
layout (std140, binding = 18, set = 0) readonly buffer Textures {
Texture textures[];
};
layout (std140, binding = 18, set = 0) readonly buffer Lights {
layout (std140, binding = 19, set = 0) readonly buffer Lights {
Light lights[];
};
layout (binding = 19, set = 1) uniform sampler2D samplerTextures[TEXTURES];
layout (binding = 20, set = 1) uniform samplerCube samplerCubemaps[CUBEMAPS];
layout (binding = 21, set = 0) uniform sampler3D samplerNoise;
layout (binding = 20, set = 1) uniform sampler2D samplerTextures[TEXTURES];
layout (binding = 21, set = 1) uniform samplerCube samplerCubemaps[CUBEMAPS];
layout (binding = 22, set = 0) uniform sampler3D samplerNoise;
#if VXGI
layout (binding = 22, set = 0) uniform sampler3D voxelOutput[CASCADES];
layout (binding = 23, set = 0) uniform sampler3D voxelOutput[CASCADES];
#endif
#if RT
layout (binding = 23, set = 0) uniform accelerationStructureEXT tlas;
layout (binding = 24, set = 0) uniform accelerationStructureEXT tlas;
#endif
#if BUFFER_REFERENCE
@ -334,11 +337,17 @@ void indirectLighting() {
#if MULTISAMPLING
void resolveSurfaceFragment() {
msaa.fragment = vec4(0.0);
msaa.depth = texelFetch(samplerDepth, ivec3(gl_GlobalInvocationID.xyz), 0).r;
for ( int i = 0; i < ubo.settings.mode.msaa; ++i ) {
msaa.currentID = i;
msaa.IDs[i] = uvec3(IMAGE_LOAD(samplerId)).xy;
if ( i > 0 ) {
float depth = texelFetch(samplerDepth, ivec3(gl_GlobalInvocationID.xyz), i).r;
msaa.depth = max(msaa.depth, depth);
}
bool unique = true;
for ( int j = msaa.currentID - 1; j >= 0; --j ) {
if ( msaa.IDs[j] == msaa.IDs[i] ) {
@ -369,5 +378,7 @@ void resolveSurfaceFragment() {
}
surface.fragment = msaa.fragment / float(ubo.settings.mode.msaa);
IMAGE_STORE( imageDepthResolved, vec4(msaa.depth, 0, 0, 0) );
}
#endif

View File

@ -102,6 +102,9 @@ void main() {
} else if ( material.modeAlpha == 2 ) {
if ( A.a < abs(material.factorAlphaCutoff) ) discard;
A.a = 1;
// alpha mode EMISSIVE
} else if ( material.modeAlpha == 3 ) {
A.a = 1;
}
if ( A.a < 0.0001 ) discard;

View File

@ -72,7 +72,7 @@ namespace pod {
uf::stl::string tag = "worldspawn";
uf::stl::string player = "info_player_spawn";
uint64_t hash = 0;
size_t hash = 0;
float lastUpdate = 0;
} stream;
} settings;

View File

@ -1,5 +1,21 @@
#undef OPAQUE
namespace pod {
struct UF_API Material {
struct AlphaMode {
static constexpr int32_t NONE = -1;
static constexpr int32_t OPAQUE = 0;
static constexpr int32_t BLEND = 1;
static constexpr int32_t MASK = 2;
static constexpr int32_t EMISSIVE = 3;
};
struct CullMode {
static constexpr int32_t DEFAULT = -1;
static constexpr int32_t NONE = 0;
};
pod::Vector4f colorBase = { 0, 0, 0, 0 };
pod::Vector4f colorEmissive = { 0, 0, 0, 0 };

View File

@ -5,7 +5,7 @@
// to-do: organize this mess
namespace impl {
uint64_t makePairKey( const pod::PhysicsBody& a, const pod::PhysicsBody& b );
size_t makePairKey( const pod::PhysicsBody& a, const pod::PhysicsBody& b );
void wakeBody( pod::PhysicsBody& body );
void sleepBody( pod::PhysicsBody& body );
void updateActivity( pod::PhysicsBody& body, float dt );

View File

@ -221,20 +221,6 @@ namespace pod {
struct BVH {
typedef uint32_t index_t;
typedef std::pair<index_t,index_t> pair_t;
struct PairHash {
size_t operator()( const pair_t& p ) const noexcept {
uint64_t a = (uint64_t) std::min(p.first, p.second);
uint64_t b = (uint64_t) std::max(p.first, p.second);
return (a << 32) ^ b;
}
};
struct PairEq {
bool operator()( const pair_t& a, const pair_t& b ) const noexcept {
return (a.first == b.first && a.second == b.second) || (a.first == b.second && a.second == b.first);
}
};
typedef uf::stl::vector<pair_t> pairs_t;
struct Node {

View File

@ -98,7 +98,8 @@ namespace {
// standard pipeline
{
uf::stl::string vertexShaderFilename = graphMetadataJson["shaders"]["vertex"].as<uf::stl::string>("/graph/base/vert.spv"); {
uf::stl::string dir = "/graph/base/";
uf::stl::string vertexShaderFilename = graphMetadataJson["shaders"]["vertex"].as<uf::stl::string>(::fmt::format("{}/{}", dir, "vert.spv" )); {
std::pair<bool, uf::stl::string> settings[] = {
{ graphMetadataJson["renderer"]["skinned"].as<bool>(), "skinned.vert" },
{ !graphMetadataJson["renderer"]["separate"].as<bool>(), "instanced.vert" },
@ -109,7 +110,11 @@ namespace {
uf::stl::string geometryShaderFilename = graphMetadataJson["shaders"]["geometry"].as<uf::stl::string>(""); if ( geometryShaderFilename != "" ) {
geometryShaderFilename = entity.resolveURI( geometryShaderFilename, root );
}
uf::stl::string fragmentShaderFilename = graphMetadataJson["shaders"]["fragment"].as<uf::stl::string>("/graph/base/frag.spv"); {
if ( graphic.descriptor.renderTarget == 1 ) {
dir = "/base/graph/";
}
uf::stl::string fragmentShaderFilename = graphMetadataJson["shaders"]["fragment"].as<uf::stl::string>(::fmt::format("{}/{}", dir, "frag.spv")); {
fragmentShaderFilename = entity.resolveURI( fragmentShaderFilename, root );
}
@ -136,12 +141,20 @@ namespace {
{
auto& shader = graphic.material.getShader("fragment");
#if UF_USE_VULKAN
uint32_t maxTextures = storage.textures.map.size();
size_t maxTextures = storage.textures.map.size();
size_t maxCubemaps = uf::config["engine"]["scenes"]["textures"]["max"]["cube"].as<size_t>(128);
size_t maxTextures3D = uf::config["engine"]["scenes"]["textures"]["max"]["3D"].as<size_t>(128);
uint32_t maxCascades = sceneTextures.voxels.id.size();
shader.setSpecializationConstants({
{ "TEXTURES", maxTextures },
{ "CUBEMAPS", maxCubemaps },
{ "CASCADES", maxCascades },
});
shader.setDescriptorCounts({
{ "samplerTextures", maxTextures },
{ "samplerCubemaps", maxCubemaps },
{ "voxelOutput", maxCascades },
});
#endif
}
@ -385,6 +398,8 @@ namespace {
shader.aliasBuffer( "material", storage.buffers.material );
shader.aliasBuffer( "texture", storage.buffers.texture );
shader.aliasBuffer( "light", storage.buffers.light );
shader.aliasBuffer( "object", storage.buffers.object );
shader.aliasBuffer( "camera", storage.buffers.camera );
}
}
@ -718,14 +733,20 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
}
// query materials if culling needs to be disabled
for ( auto& primitive : primitives ) {
auto materialID = primitive.instance.materialID;
if ( 0 <= materialID && materialID <= graph.materials.size() ) {
auto& materialName = graph.materials[materialID];
auto& material = storage.materials[materialName];
if ( material.modeCull == 0 ) {
tag["renderer"]["cull mode"] = "none";
break;
if ( entity.getName() != "worldspawn" ) {
for ( auto& primitive : primitives ) {
auto materialID = primitive.instance.materialID;
if ( 0 <= materialID && materialID <= graph.materials.size() ) {
auto& materialName = graph.materials[materialID];
auto& material = storage.materials[materialName];
if ( material.modeCull == pod::Material::CullMode::NONE ) {
tag["renderer"]["cull mode"] = "none";
}
#if UF_USE_VULKAN
if ( material.modeAlpha == pod::Material::AlphaMode::BLEND ) {
graphic.descriptor.renderTarget = 1;
}
#endif
}
}
}
@ -1032,9 +1053,10 @@ void uf::graph::process( pod::Graph& graph ) {
if ( tag["material"]["modeAlpha"].is<uf::stl::string>() ) {
const auto mode = uf::string::lowercase( tag["material"]["modeAlpha"].as<uf::stl::string>() );
if ( mode == "opaque" ) material.modeAlpha = 0;
else if ( mode == "blend" ) material.modeAlpha = 1;
else if ( mode == "mask" ) material.modeAlpha = 2;
if ( mode == "opaque" ) material.modeAlpha = pod::Material::AlphaMode::OPAQUE;
else if ( mode == "blend" ) material.modeAlpha = pod::Material::AlphaMode::BLEND;
else if ( mode == "mask" ) material.modeAlpha = pod::Material::AlphaMode::MASK;
else if ( mode == "emissive" ) material.modeAlpha = pod::Material::AlphaMode::EMISSIVE;
else UF_MSG_WARNING("Invalid AlphaMode enum string specified: {}", mode);
} else {
material.modeAlpha = tag["material"]["modeAlpha"].as(material.modeAlpha);

View File

@ -933,16 +933,17 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co
if ( vmt["$phong"].as<int>(0) == 1 ) material.factorRoughness = std::min(material.factorRoughness, 0.5f);
if ( vmt["$translucent"].as<int>(0) == 1 ) {
material.modeAlpha = 1; // BLEND
material.modeAlpha = pod::Material::AlphaMode::BLEND;
} else if ( vmt["$alphatest"].as<int>(0) == 1 ) {
material.modeAlpha = 2; // MASK
material.modeAlpha = pod::Material::AlphaMode::MASK;
material.factorAlphaCutoff = vmt["$alphatestreference"].as<float>(0.5f);
}
if ( vmt["$nocull"].as<int>(0) == 1 ) material.modeCull = 0;
if ( vmt["$nocull"].as<int>(0) == 1 ) material.modeCull = pod::Material::CullMode::NONE;
// VMTs usually define emissive masks in the albedo's alpha channel or a separate mask
// set it to a white glow for now until I can patch the shader
if ( vmt["$selfillum"].as<int>(0) == 1 ) material.colorEmissive = { 1.0f, 1.0f, 1.0f, 1.0f };
if ( vmt["$selfillum"].as<int>(0) == 1 ) {
material.colorEmissive = { 1.0f, 1.0f, 1.0f, 1.0f };
material.modeAlpha = pod::Material::AlphaMode::EMISSIVE;
}
if ( !vmt["$basetexture"].is<uf::stl::string>() ) goto PEETAH;
vtfPath = ::fmt::format("materials/{}.vtf", vmt["$basetexture"].as<uf::stl::string>());

View File

@ -339,6 +339,10 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
samples,
0
);
// cringe
if ( samples > 1 && descriptor.renderTarget == 1 ) {
multisampleState.alphaToCoverageEnable = VK_TRUE;
}
if ( samples > 1 && device.features.sampleRateShading ) {
multisampleState.sampleShadingEnable = VK_TRUE;
multisampleState.minSampleShading = 0.25f;

View File

@ -118,7 +118,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
size_t msaa = ext::vulkan::settings::msaa;
struct {
size_t id, bary, depth, uv, normal;
size_t id, bary, depth, depth_resolved, uv, normal;
size_t color, scratch, motion, output;
} attachments = {};
@ -172,7 +172,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
/*.format =*/ ext::vulkan::settings::pipelines::hdr ? enums::Format::HDR : enums::Format::SDR,
/*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
/*.blend =*/ false,
/*.blend =*/ true,
/*.samples =*/ 1,
});
attachments.scratch = renderTarget.attach(RenderTarget::Attachment::Descriptor{
@ -192,6 +192,20 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
/*.samples = */1,
});
if ( msaa > 1 ) {
attachments.depth_resolved = renderTarget.attach(RenderTarget::Attachment::Descriptor{
.format = ext::vulkan::settings::formats::depth,
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.blend = false,
.samples = 1,
.mips = 1,
});
} else {
attachments.depth_resolved = attachments.depth;
}
metadata.attachments["id"] = attachments.id;
#if BARYCENTRIC
@ -204,6 +218,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
#endif
metadata.attachments["depth"] = attachments.depth;
metadata.attachments["depth_resolved"] = attachments.depth_resolved;
metadata.attachments["color"] = attachments.color;
metadata.attachments["scratch"] = attachments.scratch;
metadata.attachments["motion"] = attachments.motion;
@ -266,7 +281,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
} attachmentsPlus = {};
attachmentsPlus.color = forwardRenderTarget.aliasAttachment(this->getAttachment("color"));
attachmentsPlus.depth = forwardRenderTarget.aliasAttachment(this->getAttachment("depth"));
attachmentsPlus.depth = forwardRenderTarget.aliasAttachment(this->getAttachment("depth_resolved"));
metadata.attachments["color+"] = attachmentsPlus.color;
metadata.attachments["depth+"] = attachmentsPlus.depth;
@ -387,6 +402,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("motion", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("depth_resolved", this, VK_IMAGE_LAYOUT_GENERAL);
}
if ( settings::pipelines::bloom ) {
@ -429,7 +445,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
auto& shader = blitter.material.getShader("compute", "dof-down");
shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("depth", this);
shader.aliasAttachment("depth_resolved", this);
shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL);
// atomic counter buffer
@ -446,7 +462,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
auto& shader = blitter.material.getShader("compute", "dof-up");
shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("depth", this);
shader.aliasAttachment("depth_resolved", this);
shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL);
{
@ -463,7 +479,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
auto& shader = blitter.material.getShader("compute", "depth-pyramid");
shader.aliasAttachment("depth", this);
shader.aliasAttachment("depth_resolved", this);
// atomic counter buffer
::postprocesses::depthPyramid.atomicCounter.initialize( (const void*) nullptr, sizeof(::AtomicCounter) * 1, uf::renderer::enums::Buffer::STORAGE );
@ -650,7 +666,7 @@ void ext::vulkan::DeferredRenderMode::tick() {
forwardRenderTarget.scale = renderTarget.scale;
forwardRenderTarget.attachments.clear();
forwardRenderTarget.aliasAttachment(this->getAttachment("color"));
forwardRenderTarget.aliasAttachment(this->getAttachment("depth"));
forwardRenderTarget.aliasAttachment(this->getAttachment("depth_resolved"));
forwardRenderTarget.initialize( *forwardRenderTarget.device );
}
@ -934,35 +950,35 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
// forward+
{
{
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "forward:setImageLayout" );
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "forward:setImageLayout" );
// Transition Color
VkImageSubresourceRange colorRange = {};
colorRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
colorRange.baseMipLevel = 0;
colorRange.levelCount = 1;
colorRange.baseArrayLayer = 0;
colorRange.layerCount = metadata.eyes; // Or this->views
// Transition Color
VkImageSubresourceRange colorRange = {};
colorRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
colorRange.baseMipLevel = 0;
colorRange.levelCount = 1;
colorRange.baseArrayLayer = 0;
colorRange.layerCount = metadata.eyes;
uf::renderer::Texture::setImageLayout(
commandBuffer,
forwardRenderTarget.attachments[0].image,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
colorRange
);
uf::renderer::Texture::setImageLayout(
commandBuffer,
forwardRenderTarget.attachments[0].image,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
colorRange
);
// Transition Depth
VkImageSubresourceRange depthRange = colorRange;
depthRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; // Depth aspect!
// Transition Depth
VkImageSubresourceRange depthRange = colorRange;
depthRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
uf::renderer::Texture::setImageLayout(
commandBuffer,
forwardRenderTarget.attachments[1].image,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
depthRange
);
uf::renderer::Texture::setImageLayout(
commandBuffer,
forwardRenderTarget.attachments[1].image,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
depthRange
);
}
renderPassBeginInfo.clearValueCount = 0;

View File

@ -35,10 +35,15 @@ namespace {
}
}
if ( image == VK_NULL_HANDLE ) continue;
bool isDepth = descriptor.name.starts_with("depth");
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
subresourceRange.aspectMask = descriptor.name == "depth" ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
uf::renderer::Texture::setImageLayout( commandBuffer, image, layout, descriptor.layout, subresourceRange );
subresourceRange.aspectMask = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
VkImageLayout oldLayout = layout;
if ( isDepth && layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) {
oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
}
uf::renderer::Texture::setImageLayout( commandBuffer, image, oldLayout, descriptor.layout, subresourceRange );
if ( mips > 1 ) {
subresourceRange.baseMipLevel = 1;
subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
@ -82,10 +87,15 @@ namespace {
}
}
if ( image == VK_NULL_HANDLE ) continue;
bool isDepth = descriptor.name.starts_with("depth");
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
subresourceRange.aspectMask = descriptor.name == "depth" ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
uf::renderer::Texture::setImageLayout( commandBuffer, image, descriptor.layout, layout, subresourceRange );
subresourceRange.aspectMask = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
VkImageLayout newLayout = layout;
if ( isDepth && layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) {
newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
}
uf::renderer::Texture::setImageLayout( commandBuffer, image, descriptor.layout, newLayout, subresourceRange );
if ( mips > 1 ) {
subresourceRange.baseMipLevel = 1;
subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;

View File

@ -1,14 +1,12 @@
#include <uf/utils/math/physics/common.h>
// create ID from pointers
uint64_t impl::makePairKey( const pod::PhysicsBody& a, const pod::PhysicsBody& b ) {
uint64_t lhs = reinterpret_cast<uint64_t>(&a);
uint64_t rhs = reinterpret_cast<uint64_t>(&b);
if (lhs > rhs) std::swap(lhs, rhs);
size_t seed = 0;
seed ^= std::hash<uint64_t>{}(lhs) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
seed ^= std::hash<uint64_t>{}(rhs) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
size_t impl::makePairKey( const pod::PhysicsBody& a, const pod::PhysicsBody& b ) {
uintptr_t lhs = reinterpret_cast<uintptr_t>(&a);
uintptr_t rhs = reinterpret_cast<uintptr_t>(&b);
if ( lhs > rhs ) std::swap(lhs, rhs);
size_t hash = uf::algo::fnv1a(lhs);
return uf::algo::fnv1a(rhs, hash);
}
// marks a body as asleep