mirror of
https://github.com/kmc-jp/n64-emu.git
synced 2025-04-02 10:21:43 -04:00
572 lines
15 KiB
C
572 lines
15 KiB
C
/* Copyright (c) 2020 Themaister
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#ifndef MEMORY_INTERFACING_H_
|
|
#define MEMORY_INTERFACING_H_
|
|
|
|
#include "dither.h"
|
|
#include "z_encode.h"
|
|
#include "blender.h"
|
|
#include "depth_test.h"
|
|
#include "coverage.h"
|
|
#include "fb_formats.h"
|
|
|
|
layout(constant_id = 0) const uint RDRAM_SIZE = 0;
|
|
|
|
layout(constant_id = 7) const int RDRAM_INCOHERENT_SCALING = 0;
|
|
const bool RDRAM_INCOHERENT = (RDRAM_INCOHERENT_SCALING & 1) != 0;
|
|
const int SCALING_LOG2 = RDRAM_INCOHERENT_SCALING >> 1;
|
|
const int SCALING_FACTOR = 1 << SCALING_LOG2;
|
|
const bool RDRAM_UNSCALED_WRITE_MASK = RDRAM_INCOHERENT && SCALING_LOG2 == 0;
|
|
const bool RDRAM_SCALED_WRITE_MASK = RDRAM_INCOHERENT && SCALING_LOG2 != 0;
|
|
|
|
const uint RDRAM_MASK_8 = RDRAM_SIZE - 1u;
|
|
const uint RDRAM_MASK_16 = RDRAM_MASK_8 >> 1u;
|
|
const uint RDRAM_MASK_32 = RDRAM_MASK_8 >> 2u;
|
|
|
|
layout(constant_id = 1) const int FB_FMT = 0;
|
|
layout(constant_id = 2) const bool FB_COLOR_DEPTH_ALIAS = false;
|
|
|
|
u8x4 current_color;
|
|
bool current_color_dirty;
|
|
|
|
u16 current_depth;
|
|
u8 current_dz;
|
|
bool current_depth_dirty;
|
|
|
|
void load_vram_color(uint index, uint slice)
|
|
{
|
|
switch (FB_FMT)
|
|
{
|
|
case FB_FMT_I4:
|
|
case FB_FMT_I8:
|
|
{
|
|
index &= RDRAM_MASK_8;
|
|
index += slice * RDRAM_SIZE;
|
|
u8 word = u8(vram8.data[index ^ 3u]);
|
|
current_color = u8x4(word, word, word, u8(hidden_vram.data[index >> 1]));
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_RGBA5551:
|
|
{
|
|
index &= RDRAM_MASK_16;
|
|
index += slice * (RDRAM_SIZE >> 1);
|
|
uint word = uint(vram16.data[index ^ 1u]);
|
|
uvec3 rgb = uvec3(word >> 8u, word >> 3u, word << 2u) & 0xf8u;
|
|
current_color = u8x4(rgb, (u8(hidden_vram.data[index]) << U8_C(5)) | u8((word & 1) << 7));
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_IA88:
|
|
{
|
|
index &= RDRAM_MASK_16;
|
|
index += slice * (RDRAM_SIZE >> 1);
|
|
uint word = uint(vram16.data[index ^ 1u]);
|
|
current_color = u8x4(u8x3(word >> 8u), word & 0xff);
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_RGBA8888:
|
|
{
|
|
index &= RDRAM_MASK_32;
|
|
index += slice * (RDRAM_SIZE >> 2);
|
|
uint word = vram32.data[index];
|
|
current_color = u8x4((uvec4(word) >> uvec4(24, 16, 8, 0)) & uvec4(0xff));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void alias_color_to_depth()
|
|
{
|
|
/* Inherit memory depth from color. */
|
|
switch (FB_FMT)
|
|
{
|
|
case FB_FMT_RGBA5551:
|
|
{
|
|
current_dz = (current_color.a >> U8_C(3)) | (current_color.b & U8_C(8));
|
|
uint word = (current_color.r & 0xf8u) << 6u;
|
|
word |= (current_color.g & 0xf8u) << 1u;
|
|
word |= (current_color.b & 0xf8u) >> 4u;
|
|
current_depth = u16(word);
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_IA88:
|
|
{
|
|
uvec2 col = current_color.ra;
|
|
uint word = (col.x << 8u) | col.y;
|
|
uint hidden_word = (word & 1u) * 3u;
|
|
current_depth = u16(word >> 2u);
|
|
current_dz = u8(((word & 3u) << 2u) | hidden_word);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void alias_depth_to_color()
|
|
{
|
|
uint word = (uint(current_depth) << 4u) | current_dz;
|
|
|
|
switch (FB_FMT)
|
|
{
|
|
case FB_FMT_RGBA5551:
|
|
{
|
|
current_color.r = u8((word >> 10u) & 0xf8u);
|
|
current_color.g = u8((word >> 5u) & 0xf8u);
|
|
current_color.b = u8((word >> 0u) & 0xf8u);
|
|
current_color.a = u8((word & 7u) << 5u);
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_IA88:
|
|
{
|
|
current_color.r = u8((word >> 10u) & 0xffu);
|
|
current_color.a = u8((word >> 2u) & 0xffu);
|
|
break;
|
|
}
|
|
}
|
|
|
|
current_color_dirty = true;
|
|
}
|
|
|
|
void load_vram_depth(uint index, uint slice)
|
|
{
|
|
index &= RDRAM_MASK_16;
|
|
index += slice * (RDRAM_SIZE >> 1);
|
|
u16 word = u16(vram16.data[index ^ 1u]);
|
|
current_depth = word >> U16_C(2);
|
|
current_dz = u8(hidden_vram.data[index]) | u8((word & U16_C(3)) << U16_C(2));
|
|
}
|
|
|
|
void store_unscaled_write_mask(uint index)
|
|
{
|
|
if (current_color_dirty)
|
|
{
|
|
switch (FB_FMT)
|
|
{
|
|
case FB_FMT_I4:
|
|
case FB_FMT_I8:
|
|
vram8.data[(index ^ 3u) + RDRAM_SIZE] = mem_u8(0xff);
|
|
break;
|
|
|
|
case FB_FMT_RGBA5551:
|
|
case FB_FMT_IA88:
|
|
vram16.data[(index ^ 1u) + (RDRAM_SIZE >> 1u)] = mem_u16(0xffff);
|
|
break;
|
|
|
|
case FB_FMT_RGBA8888:
|
|
vram32.data[index + (RDRAM_SIZE >> 2u)] = ~0u;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void store_vram_color(uint index, uint slice)
|
|
{
|
|
if (current_color_dirty)
|
|
{
|
|
switch (FB_FMT)
|
|
{
|
|
case FB_FMT_I4:
|
|
{
|
|
index &= RDRAM_MASK_8;
|
|
index += slice * RDRAM_SIZE;
|
|
vram8.data[index ^ 3u] = mem_u8(0);
|
|
if ((index & 1u) != 0u)
|
|
hidden_vram.data[index >> 1u] = mem_u8(current_color.a);
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_I8:
|
|
{
|
|
index &= RDRAM_MASK_8;
|
|
index += slice * RDRAM_SIZE;
|
|
vram8.data[index ^ 3u] = mem_u8(current_color.r);
|
|
if ((index & 1u) != 0u)
|
|
hidden_vram.data[index >> 1u] = mem_u8((current_color.r & 1) * 3);
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_RGBA5551:
|
|
{
|
|
index &= RDRAM_MASK_16;
|
|
index += slice * (RDRAM_SIZE >> 1);
|
|
uvec4 c = uvec4(current_color);
|
|
c.rgb &= 0xf8u;
|
|
uint cov = c.w >> 5u;
|
|
uint word = (c.x << 8u) | (c.y << 3u) | (c.z >> 2u) | (cov >> 2u);
|
|
vram16.data[index ^ 1u] = mem_u16(word);
|
|
hidden_vram.data[index] = mem_u8(cov & U8_C(3));
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_IA88:
|
|
{
|
|
index &= RDRAM_MASK_16;
|
|
index += slice * (RDRAM_SIZE >> 1);
|
|
uvec2 col = current_color.ra;
|
|
uint word = (col.x << 8u) | col.y;
|
|
vram16.data[index ^ 1u] = mem_u16(word);
|
|
hidden_vram.data[index] = mem_u8((col.y & 1) * 3);
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_RGBA8888:
|
|
{
|
|
index &= RDRAM_MASK_32;
|
|
index += slice * (RDRAM_SIZE >> 2);
|
|
uvec4 col = current_color;
|
|
uint word = (col.r << 24u) | (col.g << 16u) | (col.b << 8u) | (col.a << 0u);
|
|
vram32.data[index] = word;
|
|
hidden_vram.data[2u * index] = mem_u8((current_color.g & 1) * 3);
|
|
hidden_vram.data[2u * index + 1u] = mem_u8((current_color.a & 1) * 3);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (RDRAM_UNSCALED_WRITE_MASK)
|
|
{
|
|
// Need this memory barrier to ensure the mask readback does not read
|
|
// an invalid value from RDRAM. If the mask is seen, the valid RDRAM value is
|
|
// also coherent.
|
|
memoryBarrierBuffer();
|
|
store_unscaled_write_mask(index);
|
|
}
|
|
}
|
|
|
|
void store_vram_depth(uint index, uint slice)
|
|
{
|
|
if (!FB_COLOR_DEPTH_ALIAS)
|
|
{
|
|
if (current_depth_dirty)
|
|
{
|
|
index &= RDRAM_MASK_16;
|
|
index += slice * (RDRAM_SIZE >> 1);
|
|
vram16.data[index ^ 1u] = mem_u16((current_depth << U16_C(2)) | (current_dz >> U16_C(2)));
|
|
hidden_vram.data[index] = mem_u8(current_dz & U16_C(3));
|
|
}
|
|
|
|
if (RDRAM_UNSCALED_WRITE_MASK)
|
|
{
|
|
// Need this memory barrier to ensure the mask readback does not read
|
|
// an invalid value from RDRAM. If the mask is seen, the valid RDRAM value is
|
|
// also coherent.
|
|
memoryBarrierBuffer();
|
|
if (current_depth_dirty)
|
|
vram16.data[(index ^ 1) + (RDRAM_SIZE >> 1u)] = mem_u16(0xffff);
|
|
}
|
|
}
|
|
}
|
|
|
|
uint color_fb_index;
|
|
|
|
void init_tile(uvec2 coord, uint fb_width, uint fb_height, uint fb_addr_index, uint fb_depth_addr_index)
|
|
{
|
|
current_color_dirty = false;
|
|
current_depth_dirty = false;
|
|
if (all(lessThan(coord, uvec2(fb_width, fb_height))))
|
|
{
|
|
uvec2 slice2d = coord & (SCALING_FACTOR - 1);
|
|
coord >>= SCALING_LOG2;
|
|
uint slice = slice2d.y * SCALING_FACTOR + slice2d.x;
|
|
|
|
uint index = fb_addr_index + (fb_width >> SCALING_LOG2) * coord.y + coord.x;
|
|
color_fb_index = index;
|
|
load_vram_color(index, slice);
|
|
|
|
index = fb_depth_addr_index + (fb_width >> SCALING_LOG2) * coord.y + coord.x;
|
|
load_vram_depth(index, slice);
|
|
}
|
|
}
|
|
|
|
void emit_scaled_write_masks(uvec2 unscaled_coord, uint unscaled_fb_width)
|
|
{
|
|
// Merge write masks across pixels.
|
|
// We reserved a chunk of memory after scaled RDRAM to store 2 bits per pixel holding
|
|
// a write mask for color and depth. The resolve stage will only resolve a pixel
|
|
// and trigger a write if any sub-sample was marked as written.
|
|
|
|
// Write masks are organized in 4x4 blocks of unscaled pixels for locality purposes.
|
|
// This guarantees a minimum number of loop iterations to resolve the write masks.
|
|
uint unscaled_block = (unscaled_coord.y >> 2u) * ((unscaled_fb_width + 3u) >> 2u) + (unscaled_coord.x >> 2u);
|
|
uvec2 unscaled_sub = unscaled_coord & 3u;
|
|
uint word = uint(current_color_dirty) + 2u * uint(current_depth_dirty);
|
|
word <<= 2u * (unscaled_sub.x + unscaled_sub.y * 4u);
|
|
|
|
#if SUBGROUP
|
|
// This should only need one iteration .
|
|
bool is_active = true;
|
|
do
|
|
{
|
|
if (subgroupBroadcastFirst(unscaled_block) == unscaled_block)
|
|
{
|
|
uint merged = subgroupOr(word);
|
|
if (subgroupElect())
|
|
atomicOr(vram32.data[SCALING_FACTOR * SCALING_FACTOR * (RDRAM_SIZE >> 2) + unscaled_block], merged);
|
|
is_active = false;
|
|
}
|
|
} while (is_active);
|
|
#else
|
|
// Just use atomics directly. With subgroup support, we can be a bit smarter about it.
|
|
if (word != 0u)
|
|
atomicOr(vram32.data[SCALING_FACTOR * SCALING_FACTOR * (RDRAM_SIZE >> 2) + unscaled_block], word);
|
|
#endif
|
|
}
|
|
|
|
void finish_tile(uvec2 coord, uint fb_width, uint fb_height, uint fb_addr_index, uint fb_depth_addr_index)
|
|
{
|
|
// MSL portability: Need to maintain uniform control flow.
|
|
if (any(greaterThanEqual(coord, uvec2(fb_width, fb_height))))
|
|
{
|
|
current_color_dirty = false;
|
|
current_depth_dirty = false;
|
|
}
|
|
|
|
uint unscaled_fb_width = fb_width >> SCALING_LOG2;
|
|
|
|
uvec2 slice2d = coord & (SCALING_FACTOR - 1);
|
|
coord >>= SCALING_LOG2;
|
|
uint slice = slice2d.y * SCALING_FACTOR + slice2d.x;
|
|
|
|
uint index = fb_addr_index + unscaled_fb_width * coord.y + coord.x;
|
|
store_vram_color(index, slice);
|
|
|
|
index = fb_depth_addr_index + unscaled_fb_width * coord.y + coord.x;
|
|
store_vram_depth(index, slice);
|
|
|
|
if (RDRAM_SCALED_WRITE_MASK)
|
|
emit_scaled_write_masks(coord, unscaled_fb_width);
|
|
}
|
|
|
|
u8x4 decode_memory_color(bool image_read_en)
|
|
{
|
|
u8 memory_coverage = image_read_en ? (current_color.a & U8_C(0xe0)) : U8_C(0xe0);
|
|
|
|
u8x3 color;
|
|
switch (FB_FMT)
|
|
{
|
|
case FB_FMT_I4:
|
|
color = u8x3(0);
|
|
memory_coverage = U8_C(0xe0);
|
|
break;
|
|
|
|
case FB_FMT_I8:
|
|
color = current_color.rrr;
|
|
memory_coverage = U8_C(0xe0);
|
|
break;
|
|
|
|
case FB_FMT_RGBA5551:
|
|
color = current_color.rgb & U8_C(0xf8);
|
|
break;
|
|
|
|
case FB_FMT_IA88:
|
|
color = current_color.rrr;
|
|
break;
|
|
|
|
case FB_FMT_RGBA8888:
|
|
color = current_color.rgb;
|
|
break;
|
|
}
|
|
return u8x4(color, memory_coverage);
|
|
}
|
|
|
|
void write_color(u8x4 col)
|
|
{
|
|
if (FB_FMT == FB_FMT_I4)
|
|
current_color.rgb = col.rgb;
|
|
else
|
|
current_color = col;
|
|
current_color_dirty = true;
|
|
}
|
|
|
|
void copy_pipeline(uint word, uint primitive_index)
|
|
{
|
|
switch (FB_FMT)
|
|
{
|
|
case FB_FMT_I4:
|
|
{
|
|
current_color = u8x4(0);
|
|
current_color_dirty = true;
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_I8:
|
|
{
|
|
// Alpha testing needs to only look at the low dword for some bizarre reason.
|
|
// I don't think alpha testing is supposed to be used at all with 8-bit FB ...
|
|
word &= 0xffu;
|
|
write_color(u8x4(word));
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_RGBA5551:
|
|
{
|
|
uint r = (word >> 8) & 0xf8u;
|
|
uint g = (word >> 3) & 0xf8u;
|
|
uint b = (word << 2) & 0xf8u;
|
|
uint a = (word & 1) * 0xe0u;
|
|
write_color(u8x4(r, g, b, a));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (FB_COLOR_DEPTH_ALIAS)
|
|
alias_color_to_depth();
|
|
}
|
|
|
|
void fill_color(uint col)
|
|
{
|
|
switch (FB_FMT)
|
|
{
|
|
case FB_FMT_RGBA8888:
|
|
{
|
|
uint r = (col >> 24u) & 0xffu;
|
|
uint g = (col >> 16u) & 0xffu;
|
|
uint b = (col >> 8u) & 0xffu;
|
|
uint a = (col >> 0u) & 0xffu;
|
|
write_color(u8x4(r, g, b, a));
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_RGBA5551:
|
|
{
|
|
col >>= ((color_fb_index & 1u) ^ 1u) * 16u;
|
|
uint r = (col >> 8u) & 0xf8u;
|
|
uint g = (col >> 3u) & 0xf8u;
|
|
uint b = (col << 2u) & 0xf8u;
|
|
uint a = (col & 1u) * 0xe0u;
|
|
write_color(u8x4(r, g, b, a));
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_IA88:
|
|
{
|
|
col >>= ((color_fb_index & 1u) ^ 1u) * 16u;
|
|
col &= 0xffffu;
|
|
uint r = (col >> 8u) & 0xffu;
|
|
uint a = (col >> 0u) & 0xffu;
|
|
write_color(u8x4(r, r, r, a));
|
|
break;
|
|
}
|
|
|
|
case FB_FMT_I8:
|
|
{
|
|
col >>= ((color_fb_index & 3u) ^ 3u) * 8u;
|
|
col &= 0xffu;
|
|
write_color(u8x4(col));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (FB_COLOR_DEPTH_ALIAS)
|
|
alias_color_to_depth();
|
|
}
|
|
|
|
void depth_blend(int x, int y, uint primitive_index, ShadedData shaded)
|
|
{
|
|
int z = shaded.z_dith >> 9;
|
|
int dith = shaded.z_dith & 0x1ff;
|
|
int coverage_count = shaded.coverage_count;
|
|
u8x4 combined = shaded.combined;
|
|
u8 shade_alpha = shaded.shade_alpha;
|
|
|
|
uint blend_state_index = uint(state_indices.elems[primitive_index].static_depth_tmem.y);
|
|
DerivedSetup derived = load_derived_setup(primitive_index);
|
|
DepthBlendState depth_blend = load_depth_blend_state(blend_state_index);
|
|
|
|
bool force_blend = (depth_blend.flags & DEPTH_BLEND_FORCE_BLEND_BIT) != 0;
|
|
bool z_compare = (depth_blend.flags & DEPTH_BLEND_DEPTH_TEST_BIT) != 0;
|
|
bool z_update = (depth_blend.flags & DEPTH_BLEND_DEPTH_UPDATE_BIT) != 0;
|
|
bool image_read_enable = (depth_blend.flags & DEPTH_BLEND_IMAGE_READ_ENABLE_BIT) != 0;
|
|
bool color_on_coverage = (depth_blend.flags & DEPTH_BLEND_COLOR_ON_COVERAGE_BIT) != 0;
|
|
bool blend_multicycle = (depth_blend.flags & DEPTH_BLEND_MULTI_CYCLE_BIT) != 0;
|
|
bool aa_enable = (depth_blend.flags & DEPTH_BLEND_AA_BIT) != 0;
|
|
bool dither_en = (depth_blend.flags & DEPTH_BLEND_DITHER_ENABLE_BIT) != 0;
|
|
|
|
bool blend_en;
|
|
bool coverage_wrap;
|
|
u8x2 blend_shift;
|
|
|
|
u8x4 memory_color = decode_memory_color(image_read_enable);
|
|
u8 memory_coverage = memory_color.a >> U8_C(5);
|
|
|
|
bool z_pass = depth_test(z, derived.dz, derived.dz_compressed,
|
|
current_depth, current_dz,
|
|
coverage_count, memory_coverage,
|
|
z_compare, depth_blend.z_mode,
|
|
force_blend, aa_enable,
|
|
blend_en, coverage_wrap, blend_shift);
|
|
|
|
GENERIC_MESSAGE3(combined.x, combined.y, combined.z);
|
|
|
|
// Pixel tests.
|
|
if (z_pass && (!aa_enable || coverage_count != 0))
|
|
{
|
|
// Blending
|
|
BlendInputs blender_inputs =
|
|
BlendInputs(combined, memory_color,
|
|
derived.fog_color, derived.blend_color, shade_alpha);
|
|
|
|
u8x4 blend_modes = depth_blend.blend_modes0;
|
|
if (blend_multicycle)
|
|
{
|
|
blender_inputs.pixel_color.rgb =
|
|
blender(blender_inputs,
|
|
blend_modes,
|
|
force_blend, blend_en, color_on_coverage, coverage_wrap, blend_shift, false);
|
|
blend_modes = depth_blend.blend_modes1;
|
|
}
|
|
u8x3 rgb = blender(blender_inputs,
|
|
blend_modes,
|
|
force_blend, blend_en, color_on_coverage, coverage_wrap, blend_shift, true);
|
|
|
|
// Dither
|
|
if (dither_en)
|
|
rgb = rgb_dither(rgb, dith);
|
|
|
|
// Coverage blending
|
|
int new_coverage = blend_coverage(coverage_count, memory_coverage, blend_en, depth_blend.coverage_mode);
|
|
|
|
GENERIC_MESSAGE3(rgb.x, rgb.y, rgb.z);
|
|
|
|
// Writeback
|
|
write_color(u8x4(rgb, new_coverage << 5));
|
|
|
|
// Z-writeback.
|
|
if (z_update)
|
|
{
|
|
current_depth = z_compress(z);
|
|
current_dz = u8(derived.dz_compressed);
|
|
current_depth_dirty = true;
|
|
|
|
if (FB_COLOR_DEPTH_ALIAS)
|
|
alias_depth_to_color();
|
|
}
|
|
else if (FB_COLOR_DEPTH_ALIAS)
|
|
alias_color_to_depth();
|
|
}
|
|
}
|
|
|
|
#endif
|