GOOENGINE: Experimental Metal Support
Adds metal support for macOS users Original patch here: #114
This commit is contained in:
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user