GOOENGINE: Experimental Metal Support

Adds metal support for macOS users

Original patch here:
#114
This commit is contained in:
2026-02-09 12:18:59 -06:00
parent 97b553f61b
commit 353fbcc13d
15 changed files with 558 additions and 44 deletions
@@ -291,7 +291,7 @@ static void eevee_cache_finish(void *vedata)
uint tot_samples = scene_eval->eevee.taa_render_samples;
uint vl_samples = draw_ctx->view_layer->samples;
if (vl_samples > 0){
if (vl_samples > 0) {
tot_samples = vl_samples;
}
@@ -321,6 +321,10 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
grp = DRW_shgroup_material_create(gpumat, inst->probe_background);
DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f);
/* Bind all textures required by Material shaders on Metal */
EEVEE_material_bind_resources(
grp, gpumat, sldata, vedata, nullptr, nullptr, -1.0f, false, false);
}
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
@@ -41,6 +41,17 @@ static struct {
GPUTexture *util_tex;
GPUTexture *noise_tex;
#ifdef __APPLE__
/* Dummy textures for Metal. Metal requires textures to be bound and to match expected types.
* These are used as fallbacks when actual textures are not yet initialized. */
GPUTexture *dummy_cube_array; /* For probeCubes (cube array texture) */
GPUTexture *dummy_2d_array; /* For probePlanars, irradianceGrid, horizonBuffer (2D array) */
GPUTexture
*dummy_uint_2d_array; /* For shadowCubeIDTexture, shadowCascadeIDTexture (UInt 2D array) */
GPUTexture *dummy_2d; /* For refractColorBuffer (2D texture) */
GPUTexture *dummy_3d; /* For inScattering, inTransmittance (3D textures) */
#endif
float noise_offsets[3];
} e_data = {nullptr}; /* Engine data */
@@ -64,6 +75,28 @@ GPUTexture *EEVEE_materials_get_util_tex()
return e_data.util_tex;
}
#ifdef __APPLE__
GPUTexture *EEVEE_materials_get_dummy_2d_array()
{
return e_data.dummy_2d_array;
}
GPUTexture *EEVEE_materials_get_dummy_cube_array()
{
return e_data.dummy_cube_array;
}
GPUTexture *EEVEE_materials_get_dummy_2d()
{
return e_data.dummy_2d;
}
GPUTexture *EEVEE_materials_get_dummy_3d()
{
return e_data.dummy_3d;
}
#endif
void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
GPUMaterial *gpumat,
EEVEE_ViewLayerData *sldata,
@@ -82,8 +115,11 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
bool use_ao = GPU_material_flag_get(gpumat, GPU_MATFLAG_AO);
#ifdef __APPLE__
/* NOTE: Some implementation do not optimize out the unused samplers. */
/* NOTE: Metal does not optimize out unused samplers, so all textures must be bound.
* Force all conditions to true to ensure complete texture binding. */
use_diffuse = use_glossy = use_refract = use_ao = true;
use_ssrefraction = true;
use_alpha_blend = true;
#endif
LightCache *lcache = inst->g_data->light_cache;
EEVEE_EffectsInfo *effects = inst->effects;
@@ -102,42 +138,186 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
DRW_shgroup_uniform_int_copy(shgrp, "outputSssId", 1);
DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
if (use_diffuse || use_glossy || use_refract) {
#ifdef __APPLE__
/* On Metal, shadow pools may be NULL during lightbake. Use fallback textures. */
if (sldata->shadow_cube_pool != nullptr) {
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool);
}
else {
DRW_shgroup_uniform_texture(shgrp, "shadowCubeTexture", e_data.util_tex);
}
if (sldata->shadow_cascade_pool != nullptr) {
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
}
else {
DRW_shgroup_uniform_texture(shgrp, "shadowCascadeTexture", e_data.util_tex);
}
if (sldata->shadow_cube_id_pool != nullptr) {
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeIDTexture", &sldata->shadow_cube_id_pool);
}
else {
DRW_shgroup_uniform_texture(shgrp, "shadowCubeIDTexture", e_data.dummy_uint_2d_array);
}
if (sldata->shadow_cascade_id_pool != nullptr) {
DRW_shgroup_uniform_texture_ref(
shgrp, "shadowCascadeIDTexture", &sldata->shadow_cascade_id_pool);
}
else {
DRW_shgroup_uniform_texture(shgrp, "shadowCascadeIDTexture", e_data.dummy_uint_2d_array);
}
#else
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeIDTexture", &sldata->shadow_cube_id_pool);
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCascadeIDTexture", &sldata->shadow_cascade_id_pool);
#endif
}
if (use_diffuse || use_glossy || use_refract || use_ao) {
#ifdef __APPLE__
if (inst->maxzbuffer != nullptr) {
DRW_shgroup_uniform_texture_ref(shgrp, "maxzBuffer", &inst->maxzbuffer);
}
else {
DRW_shgroup_uniform_texture(shgrp, "maxzBuffer", e_data.util_tex);
}
#else
DRW_shgroup_uniform_texture_ref(shgrp, "maxzBuffer", &inst->maxzbuffer);
#endif
}
if ((use_diffuse || use_glossy) && !use_ssrefraction) {
if ((use_diffuse || use_glossy)
#ifndef __APPLE__
&& !use_ssrefraction
#endif
)
{
#ifdef __APPLE__
if (effects->gtao_horizons != nullptr) {
DRW_shgroup_uniform_texture_ref(shgrp, "horizonBuffer", &effects->gtao_horizons);
}
else {
DRW_shgroup_uniform_texture(shgrp, "horizonBuffer", e_data.util_tex);
}
#else
DRW_shgroup_uniform_texture_ref(shgrp, "horizonBuffer", &effects->gtao_horizons);
#endif
}
if (use_diffuse) {
#ifdef __APPLE__
if (lcache->grid_tx.tex != nullptr) {
DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex);
}
else {
DRW_shgroup_uniform_texture(shgrp, "irradianceGrid", e_data.dummy_2d_array);
}
#else
DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex);
#endif
}
if (use_glossy || use_refract) {
#ifdef __APPLE__
if (lcache->cube_tx.tex != nullptr) {
DRW_shgroup_uniform_texture_ref(shgrp, "probeCubes", &lcache->cube_tx.tex);
}
else {
DRW_shgroup_uniform_texture(shgrp, "probeCubes", e_data.dummy_cube_array);
}
#else
DRW_shgroup_uniform_texture_ref(shgrp, "probeCubes", &lcache->cube_tx.tex);
#endif
}
if (use_glossy) {
#ifdef __APPLE__
if (inst->planar_pool != nullptr) {
DRW_shgroup_uniform_texture_ref(shgrp, "probePlanars", &inst->planar_pool);
}
else {
DRW_shgroup_uniform_texture(shgrp, "probePlanars", e_data.dummy_2d_array);
}
if (inst->planar_depth != nullptr) {
DRW_shgroup_uniform_texture_ref(shgrp, "planarDepth", &inst->planar_depth);
}
else {
DRW_shgroup_uniform_texture(shgrp, "planarDepth", e_data.dummy_2d_array);
}
#else
DRW_shgroup_uniform_texture_ref(shgrp, "probePlanars", &inst->planar_pool);
DRW_shgroup_uniform_texture_ref(shgrp, "planarDepth", &inst->planar_depth);
#endif
DRW_shgroup_uniform_int_copy(shgrp, "outputSsrId", ssr_id ? *ssr_id : 0);
}
else {
DRW_shgroup_uniform_int_copy(shgrp, "outputSsrId", 1);
}
if (use_refract) {
DRW_shgroup_uniform_float_copy(
shgrp, "refractionDepth", (refract_depth) ? *refract_depth : 0.0);
if (use_ssrefraction) {
#ifdef __APPLE__
if (inst->filtered_radiance != nullptr) {
DRW_shgroup_uniform_texture_ref(
shgrp, "refractColorBuffer", &inst->filtered_radiance);
}
else {
DRW_shgroup_uniform_texture(shgrp, "refractColorBuffer", e_data.dummy_2d);
}
#else
DRW_shgroup_uniform_texture_ref(
shgrp, "refractColorBuffer", &inst->filtered_radiance);
#endif
}
}
if (use_alpha_blend) {
DRW_shgroup_uniform_texture_ref(shgrp, "inScattering", &effects->volume_scatter);
DRW_shgroup_uniform_texture_ref(shgrp, "inTransmittance", &effects->volume_transmit);
#ifdef __APPLE__
/* Metal: ALL surface shaders include volumetric_lib and require inScattering/inTransmittance.
* Always bind actual texture or fallback dummy - never NULL pointer reference. */
{
/* Ensure dummy_3d exists for fallback. */
if (!e_data.dummy_3d) {
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ;
e_data.dummy_3d = DRW_texture_create_3d_ex(1, 1, 1, GPU_RGBA8, usage, DRW_TEX_WRAP, nullptr);
}
GPUTexture *scatter_tex = effects->volume_scatter;
GPUTexture *transmit_tex = effects->volume_transmit;
/* Use dummy if actual is NULL. */
if (!scatter_tex) {
GPUTexture *vol_dummy = EEVEE_volumes_get_dummy_scatter();
scatter_tex = vol_dummy ? vol_dummy : e_data.dummy_3d;
}
if (!transmit_tex) {
GPUTexture *vol_dummy = EEVEE_volumes_get_dummy_transmit();
transmit_tex = vol_dummy ? vol_dummy : e_data.dummy_3d;
}
DRW_shgroup_uniform_texture(shgrp, "inScattering", scatter_tex);
DRW_shgroup_uniform_texture(shgrp, "inTransmittance", transmit_tex);
}
#else
if (use_alpha_blend) {
if (effects->volume_scatter != nullptr) {
DRW_shgroup_uniform_texture_ref(shgrp, "inScattering", &effects->volume_scatter);
}
else {
GPUTexture *dummy = EEVEE_volumes_get_dummy_scatter();
DRW_shgroup_uniform_texture(shgrp, "inScattering", dummy ? dummy : e_data.util_tex);
}
if (effects->volume_transmit != nullptr) {
DRW_shgroup_uniform_texture_ref(shgrp, "inTransmittance", &effects->volume_transmit);
}
else {
GPUTexture *dummy = EEVEE_volumes_get_dummy_transmit();
DRW_shgroup_uniform_texture(shgrp, "inTransmittance", dummy ? dummy : e_data.util_tex);
}
}
#endif
}
static void eevee_init_noise_texture()
@@ -249,6 +429,30 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
eevee_init_util_texture();
eevee_init_noise_texture();
#ifdef __APPLE__
/* Create dummy textures with correct types for Metal fallbacks.
* Metal requires all textures to be bound and to match the expected type. */
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ;
if (!e_data.dummy_2d_array) {
e_data.dummy_2d_array = DRW_texture_create_2d_array_ex(
1, 1, 1, GPU_RGBA8, usage, DRW_TEX_FILTER, nullptr);
}
if (!e_data.dummy_uint_2d_array) {
e_data.dummy_uint_2d_array = DRW_texture_create_2d_array_ex(
1, 1, 1, GPU_RGBA8UI, usage, DRW_TEX_FILTER, nullptr);
}
if (!e_data.dummy_cube_array) {
e_data.dummy_cube_array = DRW_texture_create_cube_array_ex(
1, 1, GPU_RGBA8, usage, DRW_TEX_FILTER, nullptr);
}
if (!e_data.dummy_2d) {
e_data.dummy_2d = DRW_texture_create_2d_ex(1, 1, GPU_RGBA8, usage, DRW_TEX_FILTER, nullptr);
}
if (!e_data.dummy_3d) {
e_data.dummy_3d = DRW_texture_create_3d_ex(1, 1, 1, GPU_RGBA8, usage, DRW_TEX_WRAP, nullptr);
}
#endif
}
if (draw_ctx->rv3d) {
@@ -418,6 +622,25 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex);
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
#ifdef __APPLE__
/* Metal requires all textures to be bound. */
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeIDTexture", &sldata->shadow_cube_id_pool);
DRW_shgroup_uniform_texture_ref(
grp, "shadowCascadeIDTexture", &sldata->shadow_cascade_id_pool);
GPUTexture *scatter_tex = stl->effects->volume_scatter;
GPUTexture *transmit_tex = stl->effects->volume_transmit;
if (!scatter_tex) {
GPUTexture *dummy = EEVEE_volumes_get_dummy_scatter();
scatter_tex = dummy ? dummy : e_data.dummy_3d;
}
if (!transmit_tex) {
GPUTexture *dummy = EEVEE_volumes_get_dummy_transmit();
transmit_tex = dummy ? dummy : e_data.dummy_3d;
}
DRW_shgroup_uniform_texture(grp, "inScattering", scatter_tex);
DRW_shgroup_uniform_texture(grp, "inTransmittance", transmit_tex);
#endif
DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &inst->planar_pool);
DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &inst->g_data->light_cache->cube_tx.tex);
DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &inst->g_data->light_cache->grid_tx.tex);
@@ -513,7 +736,7 @@ BLI_INLINE void material_shadow(EEVEE_Data *vedata,
ELEM(ma->blend_shadow, MA_BS_CLIP, MA_BS_HASHED);
float alpha_clip_threshold = (ma->blend_shadow == MA_BS_CLIP) ? ma->alpha_threshold : -1.0f;
int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH;
int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH | VAR_MAT_SHADOW;
SET_FLAG_FROM_TEST(mat_options, use_shadow_shader, VAR_MAT_HASH);
SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR);
GPUMaterial *gpumat = (use_shadow_shader) ?
@@ -149,6 +149,7 @@ enum {
VAR_WORLD_VOLUME = (1 << 12),
VAR_MAT_SHADOW_ID = (1 << 13),
VAR_DEFAULT = (1 << 14),
VAR_MAT_SHADOW = (1 << 15),
};
/* Material shader cache keys */
@@ -1092,6 +1093,12 @@ void eevee_id_update(void *vedata, ID *id);
/* `eevee_materials.cc` */
GPUTexture *EEVEE_materials_get_util_tex(); /* XXX */
#ifdef __APPLE__
GPUTexture *EEVEE_materials_get_dummy_2d_array();
GPUTexture *EEVEE_materials_get_dummy_cube_array();
GPUTexture *EEVEE_materials_get_dummy_3d();
#endif
void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata);
void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
@@ -1544,6 +1551,8 @@ void EEVEE_volumes_resolve(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples);
void EEVEE_volumes_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_volumes_free();
GPUTexture *EEVEE_volumes_get_dummy_scatter();
GPUTexture *EEVEE_volumes_get_dummy_transmit();
/* `eevee_effects.cc` */
@@ -1606,13 +1615,24 @@ float *EEVEE_lut_update_ggx_btdf(int lut_size, int lut_depth);
/* Shadow Matrix */
static const float texcomat[4][4] = {
/* From NDC to TexCo */
/* From NDC to TexCo (OpenGL: NDC Z is [-1,1]) */
{0.5f, 0.0f, 0.0f, 0.0f},
{0.0f, 0.5f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.5f, 0.0f},
{0.5f, 0.5f, 0.5f, 1.0f},
};
#ifdef __APPLE__
/* Metal: When using Metal-adjusted projmat (Z already in [0,1]), texcomat should NOT
* apply Z scale/offset, otherwise it's double-converted. */
static const float texcomat_metal[4][4] = {
{0.5f, 0.0f, 0.0f, 0.0f},
{0.0f, 0.5f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f}, /* Z: identity */
{0.5f, 0.5f, 0.0f, 1.0f}, /* Z offset: 0 */
};
#endif
/* Cube-map Matrices */
static const float cubefacemat[6][4][4] = {
/* Pos X */
@@ -141,7 +141,49 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input);
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &inst->maxzbuffer);
#ifdef __APPLE__
/* planarDepth: Use dummy 2D array if not available */
if (inst->planar_depth != nullptr) {
DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &inst->planar_depth);
}
else {
DRW_shgroup_uniform_texture(grp, "planarDepth", EEVEE_materials_get_dummy_2d_array());
}
/* probeCubes: Must be cube array, use dummy if not correct type */
if (lcache->cube_tx.tex != nullptr && GPU_texture_is_cube(lcache->cube_tx.tex)) {
DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex);
}
else {
DRW_shgroup_uniform_texture(grp, "probeCubes", EEVEE_materials_get_dummy_cube_array());
}
/* irradianceGrid: Must be 2D array, use dummy if wrong type */
if (lcache->grid_tx.tex != nullptr && !GPU_texture_is_cube(lcache->grid_tx.tex)) {
DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &lcache->grid_tx.tex);
}
else {
DRW_shgroup_uniform_texture(grp, "irradianceGrid", EEVEE_materials_get_dummy_2d_array());
}
/* horizonBuffer: Must be 2D texture, use util_tex as fallback */
if (effects->gtao_horizons != nullptr && !GPU_texture_is_array(effects->gtao_horizons)) {
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
}
else {
DRW_shgroup_uniform_texture(grp, "horizonBuffer", EEVEE_materials_get_util_tex());
}
/* probePlanars: 2D array fallback */
if (inst->planar_pool != nullptr) {
DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &inst->planar_pool);
}
else {
DRW_shgroup_uniform_texture(grp, "probePlanars", EEVEE_materials_get_dummy_2d_array());
}
#else
DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &inst->planar_depth);
DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex);
DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &lcache->grid_tx.tex);
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &inst->planar_pool);
#endif
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
@@ -172,19 +214,55 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
grp = DRW_shgroup_create(resolve_shader_refl, inst->ssr_resolve_refl);
}
DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input);
DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input);
#ifdef __APPLE__
/* probeCubes: Check if texture is actually a cube array (not 2D array fallback).
* Metal may fail to create cube array textures and fall back to 2D array. */
if (lcache->cube_tx.tex != nullptr && GPU_texture_is_cube(lcache->cube_tx.tex)) {
DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex);
}
else {
DRW_shgroup_uniform_texture(grp, "probeCubes", EEVEE_materials_get_dummy_cube_array());
}
if (inst->planar_pool != nullptr) {
DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &inst->planar_pool);
}
else {
DRW_shgroup_uniform_texture(grp, "probePlanars", EEVEE_materials_get_dummy_2d_array());
}
if (inst->planar_depth != nullptr) {
DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &inst->planar_depth);
DRW_shgroup_uniform_texture_ref_ex(grp, "hitBuffer", &effects->ssr_hit_output, no_filter);
DRW_shgroup_uniform_texture_ref_ex(grp, "hitDepth", &effects->ssr_hit_depth, no_filter);
DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &inst->filtered_radiance);
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &inst->maxzbuffer);
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeIDTexture", &sldata->shadow_cube_id_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeIDTexture", &sldata->shadow_cascade_id_pool);
}
else {
DRW_shgroup_uniform_texture(grp, "planarDepth", EEVEE_materials_get_dummy_2d_array());
}
#else
DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex);
DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &inst->planar_pool);
DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &inst->planar_depth);
#endif
DRW_shgroup_uniform_texture_ref_ex(grp, "hitBuffer", &effects->ssr_hit_output, no_filter);
DRW_shgroup_uniform_texture_ref_ex(grp, "hitDepth", &effects->ssr_hit_depth, no_filter);
DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &inst->filtered_radiance);
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &inst->maxzbuffer);
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeIDTexture", &sldata->shadow_cube_id_pool);
DRW_shgroup_uniform_texture_ref(
grp, "shadowCascadeIDTexture", &sldata->shadow_cascade_id_pool);
#ifdef __APPLE__
/* irradianceGrid: Check if texture is 2D array (not cube array).
* On Metal, we need to verify it's the correct type. */
if (lcache->grid_tx.tex != nullptr && !GPU_texture_is_cube(lcache->grid_tx.tex)) {
DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &lcache->grid_tx.tex);
}
else {
DRW_shgroup_uniform_texture(grp, "irradianceGrid", EEVEE_materials_get_dummy_2d_array());
}
#else
DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &lcache->grid_tx.tex);
#endif
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
@@ -194,7 +272,16 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_uniform_int(grp, "samplePoolOffset", &effects->taa_current_sample, 1);
#ifdef __APPLE__
if (effects->gtao_horizons != nullptr) {
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
}
else {
DRW_shgroup_uniform_texture(grp, "horizonBuffer", EEVEE_materials_get_util_tex());
}
#else
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
#endif
DRW_shgroup_call_procedural_triangles(grp, nullptr, 1);
}
}
@@ -225,7 +312,19 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_uniform_int(grp, "samplePoolOffset", &effects->taa_current_sample, 1);
#ifdef __APPLE__
/* horizonBuffer: Expects 2D texture. Use util_tex as fallback which is always 2D. */
if (effects->gtao_horizons != nullptr && !GPU_texture_is_array(effects->gtao_horizons)) {
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
}
else {
/* Use util_tex as it's a 2D texture (correct type for horizonBuffer) */
DRW_shgroup_uniform_texture(grp, "horizonBuffer", EEVEE_materials_get_util_tex());
}
#else
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
#endif
DRW_shgroup_call_procedural_triangles(grp, nullptr, 1);
}
}
@@ -1259,28 +1259,36 @@ static const char *eevee_get_frag_info(int options, char **r_src)
/* -- PREPASS FRAG -
* Select create info permutation for `prepass_frag`. */
const bool is_shadow = (options & VAR_MAT_SHADOW) != 0;
if (is_alpha_hash) {
/* Alpha hash material variants. */
if (is_hair) {
info_name = "eevee_legacy_material_prepass_frag_alpha_hash_hair";
info_name = is_shadow ? "eevee_legacy_material_shadow_frag_alpha_hash_hair" :
"eevee_legacy_material_prepass_frag_alpha_hash_hair";
}
else if (is_point_cloud) {
info_name = "eevee_legacy_material_prepass_frag_alpha_hash_pointcloud";
info_name = is_shadow ? "eevee_legacy_material_shadow_frag_alpha_hash_pointcloud" :
"eevee_legacy_material_prepass_frag_alpha_hash_pointcloud";
}
else {
info_name = "eevee_legacy_material_prepass_frag_alpha_hash";
info_name = is_shadow ? "eevee_legacy_material_shadow_frag_alpha_hash" :
"eevee_legacy_material_prepass_frag_alpha_hash";
}
}
else {
/* Opaque material variants. */
if (is_hair) {
info_name = "eevee_legacy_material_prepass_frag_opaque_hair";
info_name = is_shadow ? "eevee_legacy_material_shadow_frag_opaque_hair" :
"eevee_legacy_material_prepass_frag_opaque_hair";
}
else if (is_point_cloud) {
info_name = "eevee_legacy_material_prepass_frag_opaque_pointcloud";
info_name = is_shadow ? "eevee_legacy_material_shadow_frag_opaque_pointcloud" :
"eevee_legacy_material_prepass_frag_opaque_pointcloud";
}
else {
info_name = "eevee_legacy_material_prepass_frag_opaque";
info_name = is_shadow ? "eevee_legacy_material_shadow_frag_opaque" :
"eevee_legacy_material_prepass_frag_opaque";
}
}
*r_src = BLI_strdup(e_data.surface_prepass_frag);
@@ -1346,6 +1354,9 @@ static char *eevee_get_defines(int options)
if ((options & VAR_MAT_SHADOW_ID) != 0) {
BLI_dynstr_append(ds, "#define USE_SHADOW_ID\n");
}
if ((options & VAR_MAT_SHADOW) != 0) {
BLI_dynstr_append(ds, "#define SHADOW_PASS\n");
}
str = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
@@ -74,9 +74,13 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
}
/* GooEngine: Set Depth node can write to gl_FragDepth arbitrarily.
* Only enable depth_write for materials that actually use Set Depth node
* to avoid black speckle artifacts on Metal.
* This shouldn't incur a performance penalty according to
* https://registry.khronos.org/OpenGL/extensions/ARB/ARB_conservative_depth.txt */
info.depth_write(DepthWrite::ANY);
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SET_DEPTH)) {
info.depth_write(DepthWrite::ANY);
}
/* Lookdev - Add FragDepth. */
if (options & VAR_MAT_LOOKDEV) {
@@ -57,9 +57,13 @@ void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata)
int sh_cube_size = scene_eval->eevee.shadow_cube_size;
int sh_cascade_size = scene_eval->eevee.shadow_cascade_size;
const bool sh_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_HIGH_BITDEPTH) != 0;
const bool sh_id_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_ID_HIGH_BITDEPTH) != 0;
const bool sh_id_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_ID_HIGH_BITDEPTH) !=
0;
sldata->lights->soft_shadows = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_SOFT) != 0;
CLAMP(sh_cube_size, 256, 4096);
CLAMP(sh_cascade_size, 256, 4096);
EEVEE_LightsInfo *linfo = sldata->lights;
if ((linfo->shadow_cube_size != sh_cube_size) ||
(linfo->shadow_high_bitdepth != sh_high_bitdepth) ||
@@ -68,7 +72,6 @@ void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata)
BLI_assert((sh_cube_size > 0) && (sh_cube_size <= 4096));
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_id_pool);
CLAMP(sh_cube_size, 1, 4096);
}
if ((linfo->shadow_cascade_size != sh_cascade_size) ||
@@ -78,7 +81,6 @@ void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata)
BLI_assert((sh_cascade_size > 0) && (sh_cascade_size <= 4096));
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_id_pool);
CLAMP(sh_cascade_size, 1, 4096);
}
linfo->shadow_high_bitdepth = sh_high_bitdepth;
@@ -108,7 +110,8 @@ void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
INIT_MINMAX(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max);
{
DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_SHADOW_OFFSET | DRW_STATE_WRITE_COLOR;
DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_SHADOW_OFFSET |
DRW_STATE_WRITE_COLOR;
DRW_PASS_CREATE(inst->shadow_pass, state);
inst->g_data->shadow_shgrp = DRW_shgroup_create(EEVEE_shaders_shadow_sh_get(),
@@ -211,7 +214,8 @@ void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
eGPUTextureFormat shadow_pool_format = (linfo->shadow_high_bitdepth) ? GPU_DEPTH_COMPONENT24 :
GPU_DEPTH_COMPONENT16;
eGPUTextureFormat shadow_id_pool_format = (linfo->shadow_id_high_bitdepth) ? GPU_R32UI : GPU_R16UI;
eGPUTextureFormat shadow_id_pool_format = (linfo->shadow_id_high_bitdepth) ? GPU_R32UI :
GPU_R16UI;
/* Setup enough layers. */
/* Free textures if number mismatch. */
@@ -246,6 +250,17 @@ void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
shadow_id_pool_format,
static_cast<DRWTextureFlag>(0),
nullptr);
/* GooEngine Fix: Manually clear all layers to 1.0 (Far) to prevent black artifacts. */
GPUFrameBuffer *tmp_fb = GPU_framebuffer_create("shadow_clear_fb");
int layers = max_ii(1, linfo->num_cube_layer * 6);
for (int i = 0; i < layers; i++) {
GPU_framebuffer_texture_layer_attach(tmp_fb, sldata->shadow_cube_pool, 0, i, 0);
GPU_framebuffer_bind(tmp_fb);
GPU_framebuffer_clear_depth(tmp_fb, 1.0f);
}
GPU_framebuffer_free(tmp_fb);
GPU_framebuffer_restore();
}
if (!sldata->shadow_cascade_pool) {
@@ -257,12 +272,24 @@ void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
shadow_usage,
DRWTextureFlag(DRW_TEX_FILTER | DRW_TEX_COMPARE),
nullptr);
sldata->shadow_cascade_id_pool = DRW_texture_create_2d_array(linfo->shadow_cascade_size,
linfo->shadow_cascade_size,
max_ii(1, linfo->num_cascade_layer),
shadow_id_pool_format,
static_cast<DRWTextureFlag>(0),
nullptr);
sldata->shadow_cascade_id_pool = DRW_texture_create_2d_array(
linfo->shadow_cascade_size,
linfo->shadow_cascade_size,
max_ii(1, linfo->num_cascade_layer),
shadow_id_pool_format,
static_cast<DRWTextureFlag>(0),
nullptr);
/* GooEngine Fix: Manually clear all layers to 1.0 (Far) to prevent black artifacts. */
GPUFrameBuffer *tmp_fb = GPU_framebuffer_create("shadow_clear_fb");
int layers = max_ii(1, linfo->num_cascade_layer);
for (int i = 0; i < layers; i++) {
GPU_framebuffer_texture_layer_attach(tmp_fb, sldata->shadow_cascade_pool, 0, i, 0);
GPU_framebuffer_bind(tmp_fb);
GPU_framebuffer_clear_depth(tmp_fb, 1.0f);
}
GPU_framebuffer_free(tmp_fb);
GPU_framebuffer_restore();
}
if (sldata->shadow_fb == nullptr) {
@@ -408,16 +435,24 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata,
void EEVEE_shadow_output_accumulate(EEVEE_ViewLayerData * /*sldata*/, EEVEE_Data *vedata)
{
GOOENGINE_Instance *inst = vedata->instance;
EEVEE_EffectsInfo *effects = inst->effects;
if (inst->shadow_accum_fb != nullptr) {
GPU_framebuffer_bind(inst->shadow_accum_fb);
/* Clear texture. */
#ifdef __APPLE__
/* Metal: Always clear shadow accumulation buffer to prevent stale data
* when switching between viewports/workspaces. This fixes issue where
* shadow intensity changes unexpectedly due to TAA not resetting properly. */
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(fbl->shadow_accum_fb, clear);
#else
EEVEE_EffectsInfo *effects = inst->effects;
if (effects->taa_current_sample == 1) {
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(inst->shadow_accum_fb, clear);
}
#endif
DRW_draw_pass(inst->shadow_accum_pass);
@@ -354,9 +354,25 @@ static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo,
add_v2_v2(projmat[3], jitter_ofs);
}
#ifdef __APPLE__
/* Metal: Adjust projection matrix for depth range [0, 1] instead of [-1, 1].
* z_metal = (z_opengl + 1) / 2 = z_opengl * 0.5 + 0.5
* CRITICAL: This must come BEFORE shadowmat calculation so that both
* shadow map rendering and shadow sampling use the same depth range. */
projmat[2][2] *= 0.5f;
projmat[3][2] = projmat[3][2] * 0.5f + 0.5f;
#endif
/* Calculate shadow matrix for sampling. */
float viewprojmat[4][4];
mul_m4_m4m4(viewprojmat, projmat, viewmat);
#ifdef __APPLE__
/* Metal: Use texcomat_metal which doesn't apply Z transform since
* projmat already produces Z in [0, 1] range after above adjustment. */
mul_m4_m4m4(csm_data->shadowmat[c], texcomat_metal, viewprojmat);
#else
mul_m4_m4m4(csm_data->shadowmat[c], texcomat, viewprojmat);
#endif
#ifdef DEBUG_CSM
DRW_debug_m4_as_bbox(viewprojmat, true, dbg_col);
@@ -140,6 +140,15 @@ static void eevee_ensure_cube_views(
perspective_m4(winmat, -side, side, -side, side, near, far);
#ifdef __APPLE__
/* Metal: Adjust projection matrix for depth range [0, 1] instead of [-1, 1].
* z_metal = (z_opengl + 1) / 2 = z_opengl * 0.5 + 0.5
* For perspective matrix: z_clip = winmat[2][2] * z + winmat[3][2]
* After Metal adjustment: z_clip_metal = z_clip * 0.5 + 0.5 */
winmat[2][2] *= 0.5f;
winmat[3][2] = winmat[3][2] * 0.5f + 0.5f;
#endif
for (int i = 0; i < 6; i++) {
float tmp[4][4];
mul_m4_m4m4(tmp, cubefacemat[i], viewmat);
@@ -205,7 +214,8 @@ void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
DRW_view_set_active(g_data->cube_views[j]);
int layer = cube_index * 6 + j;
GPU_framebuffer_texture_layer_attach(sldata->shadow_fb, sldata->shadow_cube_pool, 0, layer, 0);
GPU_framebuffer_texture_layer_attach(sldata->shadow_fb, sldata->shadow_cube_id_pool, 1, layer, 0);
GPU_framebuffer_texture_layer_attach(
sldata->shadow_fb, sldata->shadow_cube_id_pool, 1, layer, 0);
GPU_framebuffer_bind(sldata->shadow_fb);
GPU_framebuffer_clear_depth(sldata->shadow_fb, 1.0f);
DRW_draw_pass(inst->shadow_pass);
@@ -369,7 +369,8 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeIDTexture", &sldata->shadow_cube_id_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeIDTexture", &sldata->shadow_cascade_id_pool);
DRW_shgroup_uniform_texture_ref(
grp, "shadowCascadeIDTexture", &sldata->shadow_cascade_id_pool);
DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &inst->volume_prop_scattering);
DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &inst->volume_prop_extinction);
DRW_shgroup_uniform_texture_ref(grp, "volumeEmission", &inst->volume_prop_emission);
@@ -598,6 +599,16 @@ void EEVEE_volumes_free()
DRW_TEXTURE_FREE_SAFE(e_data.dummy_flame);
}
GPUTexture *EEVEE_volumes_get_dummy_scatter()
{
return e_data.dummy_scatter;
}
GPUTexture *EEVEE_volumes_get_dummy_transmit()
{
return e_data.dummy_transmit;
}
/* -------------------------------------------------------------------- */
/** \name Render Passes
* \{ */
@@ -150,7 +150,7 @@ GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_prepass_frag_common)
ADDITIONAL_INFO(eevee_legacy_common_lib)
ADDITIONAL_INFO(eevee_legacy_common_utiltex_lib)
FRAGMENT_OUT(1, UINT, resource_id_out)
/* FRAGMENT_OUT(1, UINT, resource_id_out) */
ADDITIONAL_INFO(draw_view)
ADDITIONAL_INFO(eevee_legacy_closure_eval_surface_lib)
GPU_SHADER_CREATE_END()
@@ -163,17 +163,20 @@ GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_prepass_frag_opaque)
ADDITIONAL_INFO(eevee_legacy_surface_lib_common)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_opaque_common)
FRAGMENT_OUT(1, VEC2, out_normal);
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_prepass_frag_opaque_hair)
ADDITIONAL_INFO(eevee_legacy_surface_lib_hair)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_opaque_common)
ADDITIONAL_INFO(draw_hair)
FRAGMENT_OUT(1, VEC2, out_normal);
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_prepass_frag_opaque_pointcloud)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_opaque_common)
ADDITIONAL_INFO(draw_pointcloud)
FRAGMENT_OUT(1, VEC2, out_normal);
GPU_SHADER_CREATE_END()
/* Common info for all `prepass_frag_alpha_hash` variants. */
@@ -186,18 +189,58 @@ GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_prepass_frag_alpha_hash)
ADDITIONAL_INFO(eevee_legacy_surface_lib_common)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_alpha_hash_common)
FRAGMENT_OUT(1, VEC2, out_normal);
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_prepass_frag_alpha_hash_hair)
ADDITIONAL_INFO(eevee_legacy_surface_lib_hair)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_alpha_hash_common)
ADDITIONAL_INFO(draw_hair)
FRAGMENT_OUT(1, VEC2, out_normal);
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_prepass_frag_alpha_hash_pointcloud)
ADDITIONAL_INFO(eevee_legacy_surface_lib_pointcloud)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_alpha_hash_common)
ADDITIONAL_INFO(draw_pointcloud)
FRAGMENT_OUT(1, VEC2, out_normal);
GPU_SHADER_CREATE_END()
/* Shadow Variants (Same as prepass but NO Normal Output) */
GPU_SHADER_CREATE_INFO(eevee_legacy_material_shadow_frag_opaque)
ADDITIONAL_INFO(eevee_legacy_surface_lib_common)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_opaque_common)
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_shadow_frag_opaque_hair)
ADDITIONAL_INFO(eevee_legacy_surface_lib_hair)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_opaque_common)
ADDITIONAL_INFO(draw_hair)
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_shadow_frag_opaque_pointcloud)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_opaque_common)
ADDITIONAL_INFO(draw_pointcloud)
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_shadow_frag_alpha_hash)
ADDITIONAL_INFO(eevee_legacy_surface_lib_common)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_alpha_hash_common)
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_shadow_frag_alpha_hash_hair)
ADDITIONAL_INFO(eevee_legacy_surface_lib_hair)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_alpha_hash_common)
ADDITIONAL_INFO(draw_hair)
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(eevee_legacy_material_shadow_frag_alpha_hash_pointcloud)
ADDITIONAL_INFO(eevee_legacy_surface_lib_pointcloud)
ADDITIONAL_INFO(eevee_legacy_material_prepass_frag_alpha_hash_common)
ADDITIONAL_INFO(draw_pointcloud)
FRAGMENT_OUT(1, VEC2, out_normal);
GPU_SHADER_CREATE_END()
/** \} */
@@ -182,7 +182,7 @@ float sample_ID_texture(usampler2DArray TEX_ID, vec3 coord, bool match)
ivec3 tex_size = textureSize(TEX_ID, 0);
// WHY THE FLYING FUCK DO WE NEED AN EXTRA 0.00195?
vec2 fra = fract((coord.xy * tex_size.xy) + vec2(0.50195, 0.50195));
vec2 fra = fract((coord.xy * vec2(tex_size.xy)) + vec2(0.50195, 0.50195));
return mix(
mix(matches.w, matches.z, fra.x),
@@ -203,6 +203,16 @@ float sample_cube_shadow(int shadow_id, vec3 P, bool match_shadow_id)
vec3 cubevec = transform_point(scube(data_id).shadowmat, P);
float dist = max(sd(shadow_id).sh_near, max_v3(abs(cubevec)) - sd(shadow_id).sh_bias);
dist = buffer_depth(true, dist, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
/* Metal: buffer_depth outputs OpenGL depth range.
* Adjust to Metal depth range [0, 1] by transforming from [-1, 1] -> [0, 1].
* GPU projection matrices should already handle this, but buffer_depth uses
* raw perspective formula. */
#ifdef GPU_METAL
/* Clamp to [0, 1] to prevent comparison issues */
dist = clamp(dist, 0.0, 1.0);
#endif
/* Manual Shadow Cube Layer indexing. */
/* TODO: Shadow Cube Array. */
float face = cubeFaceIndexEEVEE(cubevec);
@@ -217,6 +227,8 @@ float sample_cube_shadow(int shadow_id, vec3 P, bool match_shadow_id)
return texture(shadowCubeTexture, coord_f);
#endif
}
/* Uncomment to debug shadow depth values - will show depth as grayscale */
float sample_cascade_shadow(int shadow_id, vec3 P, bool match_shadow_id)
{
@@ -232,9 +244,19 @@ float sample_cascade_shadow(int shadow_id, vec3 P, bool match_shadow_id)
float blend = fract(tot_weight);
float vis = weights.w;
vec4 coord, shpos;
float compare_z;
/* Main cascade. */
shpos = scascade(data_id).shadowmat[cascade] * vec4(P, 1.0);
coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
compare_z = shpos.z - sd(shadow_id).sh_bias;
/* Metal: Ensure comparison depth is in [0, 1] range */
#ifdef GPU_METAL
compare_z = clamp(compare_z, 0.0, 1.0);
#endif
coord = vec4(shpos.xy, tex_id + float(cascade), compare_z);
#ifdef USE_SHADOW_ID
float id_sample = sample_ID_texture(shadowCascadeIDTexture, coord.xyz, match_shadow_id);
vis += min(texture(shadowCascadeTexture, coord) + id_sample, 1.0) * (1.0 - blend);
@@ -245,7 +267,14 @@ float sample_cascade_shadow(int shadow_id, vec3 P, bool match_shadow_id)
cascade = min(3, cascade + 1);
/* Second cascade. */
shpos = scascade(data_id).shadowmat[cascade] * vec4(P, 1.0);
coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
compare_z = shpos.z - sd(shadow_id).sh_bias;
/* Metal: Ensure comparison depth is in [0, 1] range */
#ifdef GPU_METAL
compare_z = clamp(compare_z, 0.0, 1.0);
#endif
coord = vec4(shpos.xy, tex_id + float(cascade), compare_z);
#ifdef USE_SHADOW_ID
id_sample = sample_ID_texture(shadowCascadeIDTexture, coord.xyz, match_shadow_id);
vis += min(texture(shadowCascadeTexture, coord) + id_sample, 1.0) * blend;
@@ -92,7 +92,15 @@ void main()
}
#endif
resource_id_out = resource_id;
/* resource_id_out = resource_id; */
/* GooEngine Fix: Output Normal to RG16 buffer (Loc 1).
* Use viewNormal from vertex shader interface, which is always initialized.
* g_data.N is only initialized when USE_ALPHA_HASH is defined. */
#ifndef SHADOW_PASS
/* viewNormal comes from surface_lib interface, already in view space. */
vec3 N = normalize(viewNormal);
out_normal = normal_encode(N, vec3(0.0));
#endif
}
/* Passthrough. */
+1
View File
@@ -94,6 +94,7 @@ enum eGPUMaterialFlag {
/* HACK(fclem) Tells the environment texture node to not bail out if empty. */
GPU_MATFLAG_LOOKDEV_HACK = (1 << 30),
GPU_MATFLAG_SET_DEPTH = (1 << 31),
};
ENUM_OPERATORS(eGPUMaterialFlag, GPU_MATFLAG_LOOKDEV_HACK);