Implement depth textures and shadow mapping in DirectX 9 renderer

(at long last)
This commit is contained in:
rdb 2015-11-26 01:04:26 +01:00
parent a819e9055b
commit fb317e3b7a
5 changed files with 207 additions and 74 deletions

View File

@ -2647,6 +2647,18 @@ reset() {
}
}
_supports_depth_stencil = ((_screen->_supported_tex_formats_mask & D24S8_FLAG) != 0);
_supports_depth_texture = _supports_depth_stencil ||
(_screen->_supported_tex_formats_mask & D16_FLAG) != 0 ||
(_screen->_supported_tex_formats_mask & D32_FLAG) != 0 ||
(_screen->_supported_tex_formats_mask & D24X8_FLAG) != 0;
// In DirectX 9, all built-in depth formats use shadow map filtering. Some
// drivers (GeForce 8000+, Radeon HD 4000+, Intel G45+) expose a FourCC
// format called "INTZ" that allows access to the actual depth. We don't
// have a flag to indicate this, though.
_supports_shadow_filter = _supports_depth_texture;
// check if compressed textures are supported
#define CHECK_FOR_DXTVERSION(num) \
if (_screen->_supported_tex_formats_mask & DXT##num##_FLAG) {\

View File

@ -119,6 +119,8 @@ create_texture(DXScreenData &scrn) {
int num_alpha_bits; // number of alpha bits in texture pixfmt
D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN;
bool needs_luminance = false;
bool needs_depth = false;
bool needs_stencil = false;
bool compress_texture = false;
Texture *tex = get_texture();
@ -190,53 +192,75 @@ create_texture(DXScreenData &scrn) {
DWORD target_bpp = get_bits_per_pixel(tex->get_format(), &num_alpha_bits);
DWORD num_color_channels = tex->get_num_components();
// printf ("format = %d \n", tex->get_format());
// printf ("target_bpp %d, num_color_channels %d num_alpha_bits %d \n", target_bpp, num_color_channels, num_alpha_bits);
//PRINT_REFCNT(dxgsg9, scrn._d3d9);
if ((tex->get_format() == Texture::F_luminance_alpha)||
(tex->get_format() == Texture::F_luminance_alphamask) ||
(tex->get_format() == Texture::F_luminance) ||
(tex->get_format() == Texture::F_sluminance_alpha) ||
(tex->get_format() == Texture::F_sluminance)) {
needs_luminance = true;
}
if (num_alpha_bits > 0) {
if (num_color_channels == 3) {
dxgsg9_cat.error()
<< "texture " << tex->get_name()
<< " has no inherent alpha channel, but alpha format is requested!\n";
}
}
_d3d_format = D3DFMT_UNKNOWN;
// figure out what 'D3DFMT' the Texture is in, so D3DXLoadSurfFromMem knows how to perform copy
switch (num_color_channels) {
case 1:
if (num_alpha_bits > 0) {
_d3d_format = D3DFMT_A8;
} else if (needs_luminance) {
_d3d_format = D3DFMT_L8;
}
switch (tex->get_format()) {
case Texture::F_depth_stencil:
_d3d_format = D3DFMT_D24S8;
needs_depth = true;
needs_stencil = true;
break;
case 2:
nassertr(needs_luminance && (num_alpha_bits > 0), false);
case Texture::F_depth_component:
case Texture::F_depth_component16:
_d3d_format = D3DFMT_D16;
needs_depth = true;
break;
case Texture::F_depth_component24:
_d3d_format = D3DFMT_D24X8;
needs_depth = true;
break;
case Texture::F_depth_component32:
_d3d_format = D3DFMT_D32;
needs_depth = true;
break;
case Texture::F_luminance:
case Texture::F_sluminance:
_d3d_format = D3DFMT_L8;
needs_luminance = true;
break;
case Texture::F_luminance_alpha:
case Texture::F_luminance_alphamask:
case Texture::F_sluminance_alpha:
_d3d_format = D3DFMT_A8L8;
needs_luminance = true;
break;
case 3:
_d3d_format = D3DFMT_R8G8B8;
break;
case 4:
_d3d_format = D3DFMT_A8R8G8B8;
break;
}
// make sure we handled all the possible cases
nassertr(_d3d_format != D3DFMT_UNKNOWN, false);
default:
if (num_alpha_bits > 0) {
if (num_color_channels == 3) {
dxgsg9_cat.error()
<< "texture " << tex->get_name()
<< " has no inherent alpha channel, but alpha format is requested!\n";
}
}
_d3d_format = D3DFMT_UNKNOWN;
switch (num_color_channels) {
case 1:
if (num_alpha_bits > 0) {
_d3d_format = D3DFMT_A8;
}
break;
case 2:
nassertr(false && (num_alpha_bits > 0), false);
_d3d_format = D3DFMT_A8L8;
break;
case 3:
_d3d_format = D3DFMT_R8G8B8;
break;
case 4:
_d3d_format = D3DFMT_A8R8G8B8;
break;
}
// make sure we handled all the possible cases
nassertr(_d3d_format != D3DFMT_UNKNOWN, false);
}
DWORD target_width = orig_width;
DWORD target_height = orig_height;
@ -447,6 +471,14 @@ create_texture(DXScreenData &scrn) {
goto found_matching_format;
case 32:
if (needs_depth) {
nassertr(num_alpha_bits == 0, false);
nassertr(num_color_channels == 1, false);
CHECK_FOR_FMT(D32);
break;
}
if (!((num_color_channels == 3) || (num_color_channels == 4)))
break; //bail
@ -494,25 +526,78 @@ create_texture(DXScreenData &scrn) {
break;
case 24:
nassertr(num_color_channels == 3, false);
if (needs_depth) {
nassertr(num_alpha_bits == 0, false);
nassertr(num_color_channels == 1, false);
CHECK_FOR_FMT(R8G8B8);
// In DirectX 9, all built-in depth formats use shadow map filtering.
// Some drivers (GeForce 8000+, Radeon HD 4000+, Intel G45+) expose a
// FourCC format called "INTZ" that allows access to the actual depth.
if (tex->get_minfilter() == Texture::FT_shadow) {
if (needs_stencil) {
CHECK_FOR_FMT(D24S8);
}
CHECK_FOR_FMT(D24X8);
CHECK_FOR_FMT(D32);
CHECK_FOR_FMT(D16);
} else {
if (scrn._supported_tex_formats_mask & INTZ_FLAG) {
target_pixel_format = (D3DFORMAT)MAKEFOURCC('I', 'N', 'T', 'Z');
goto found_matching_format;
}
// no 24-bit fmt. look for 32 bit fmt (note: this is
// memory-hogging choice instead I could look for
// memory-conserving 16-bit fmt).
// We fall back to a depth format. Chances are that it is going to
// be used for shadow mapping, in which case the depth comparison
// will probably still result in a useful value.
CHECK_FOR_FMT(D24X8);
}
} else {
nassertr(num_color_channels == 3, false);
CHECK_FOR_FMT(X8R8G8B8);
CHECK_FOR_FMT(A8R8G8B8);
CHECK_FOR_FMT(R8G8B8);
// no 24-bit or 32 fmt. look for 16 bit fmt (higher res 565 1st)
CHECK_FOR_FMT(R5G6B5);
CHECK_FOR_FMT(X1R5G5B5);
CHECK_FOR_FMT(A1R5G5B5);
// no 24-bit fmt. look for 32 bit fmt (note: this is
// memory-hogging choice instead I could look for
// memory-conserving 16-bit fmt).
CHECK_FOR_FMT(X8R8G8B8);
CHECK_FOR_FMT(A8R8G8B8);
// no 24-bit or 32 fmt. look for 16 bit fmt (higher res 565 1st)
CHECK_FOR_FMT(R5G6B5);
CHECK_FOR_FMT(X1R5G5B5);
CHECK_FOR_FMT(A1R5G5B5);
}
break;
case 16:
if (needs_luminance) {
if (needs_depth) {
nassertr(num_alpha_bits == 0, false);
nassertr(num_color_channels == 1, false);
// In DirectX 9, all built-in depth formats use shadow map filtering.
// Some drivers (GeForce 8000+, Radeon HD 4000+, Intel G45+) expose a
// FourCC format called "INTZ" that allows access to the actual depth.
if (tex->get_minfilter() == Texture::FT_shadow) {
if (needs_stencil) {
CHECK_FOR_FMT(D24S8);
}
CHECK_FOR_FMT(D16);
CHECK_FOR_FMT(D24X8);
CHECK_FOR_FMT(D32);
} else {
if (scrn._supported_tex_formats_mask & INTZ_FLAG) {
target_pixel_format = (D3DFORMAT)MAKEFOURCC('I', 'N', 'T', 'Z');
goto found_matching_format;
}
// We fall back to a depth format. Chances are that it is going to
// be used for shadow mapping, in which case the depth comparison
// will probably still result in a useful value.
CHECK_FOR_FMT(D24X8);
}
} else if (needs_luminance) {
nassertr(num_alpha_bits > 0, false);
nassertr(num_color_channels == 2, false);
@ -613,11 +698,13 @@ create_texture(DXScreenData &scrn) {
// Instead of creating a texture with the found format, we will
// need to make one that exactly matches the framebuffer's
// format. Look up what that format is.
DWORD render_target_index;
IDirect3DSurface9 *render_target;
render_target_index = 0;
hr = scrn._d3d_device->GetRenderTarget(render_target_index, &render_target);
if (needs_depth) {
hr = scrn._d3d_device->GetDepthStencilSurface(&render_target);
} else {
hr = scrn._d3d_device->GetRenderTarget(0, &render_target);
}
if (FAILED(hr)) {
dxgsg9_cat.error()
<< "GetRenderTgt failed in create_texture: " << D3DERRORSTRING(hr);
@ -628,7 +715,8 @@ create_texture(DXScreenData &scrn) {
dxgsg9_cat.error()
<< "GetDesc failed in create_texture: " << D3DERRORSTRING(hr);
} else {
if (target_pixel_format != surface_desc.Format) {
if (target_pixel_format != surface_desc.Format &&
target_pixel_format != MAKEFOURCC('I', 'N', 'T', 'Z')) {
if (dxgsg9_cat.is_debug()) {
dxgsg9_cat.debug()
<< "Chose format " << D3DFormatStr(surface_desc.Format)
@ -786,10 +874,14 @@ create_texture(DXScreenData &scrn) {
_is_render_target = true;
pool = D3DPOOL_DEFAULT;
usage = D3DUSAGE_RENDERTARGET;
if (target_bpp <= 32 ) {
target_pixel_format = scrn._render_to_texture_d3d_format;
if (needs_depth) {
usage = D3DUSAGE_DEPTHSTENCIL;
} else {
usage = D3DUSAGE_RENDERTARGET;
}
//if (target_bpp <= 32) {
// target_pixel_format = scrn._render_to_texture_d3d_format;
//}
dxgsg9_cat.debug ()
<< "*** RENDER TO TEXTURE ***: format "
@ -1126,6 +1218,22 @@ extract_texture_data(DXScreenData &screen) {
format = Texture::F_luminance_alpha;
break;
case D3DFMT_D24S8:
format = Texture::F_depth_stencil;
break;
case D3DFMT_D16:
format = Texture::F_depth_component16;
break;
case D3DFMT_D24X8:
format = Texture::F_depth_component24;
break;
case D3DFMT_D32:
format = Texture::F_depth_component32;
break;
case D3DFMT_DXT1:
compression = Texture::CM_dxt1;
div = 4;
@ -2159,8 +2267,12 @@ get_bits_per_pixel(Texture::Format format, int *alphbits) {
*alphbits = 1;
return 16;
case Texture::F_depth_component:
case Texture::F_depth_component16:
return 16;
case Texture::F_depth_stencil:
case Texture::F_depth_component24:
return 24;
case Texture::F_depth_component32:
return 32;
case Texture::F_rgb5:
return 16;
@ -2233,6 +2345,8 @@ d3d_format_to_bytes_per_pixel (D3DFORMAT format)
case D3DFMT_A8L8:
case D3DFMT_A8R3G3B2:
case D3DFMT_X4R4G4B4:
case D3DFMT_D16:
case (D3DFORMAT)MAKEFOURCC('D', 'F', '1', '6'):
bytes_per_pixel = 2.0f;
break;
@ -2251,6 +2365,11 @@ d3d_format_to_bytes_per_pixel (D3DFORMAT format)
case D3DFMT_X8B8G8R8:
case D3DFMT_G16R16:
case D3DFMT_A2R10G10B10:
case D3DFMT_D24X8:
case D3DFMT_D24S8:
case D3DFMT_D32:
case (D3DFORMAT)MAKEFOURCC('D', 'F', '2', '4'):
case (D3DFORMAT)MAKEFOURCC('I', 'N', 'T', 'Z'):
bytes_per_pixel = 4.0f;
break;

View File

@ -165,11 +165,11 @@ typedef enum {
L8_FLAG = FLG(15),
A8L8_FLAG = FLG(16),
A4L4_FLAG = FLG(17),
V8U8_FLAG = FLG(18),
L6V5U5_FLAG = FLG(19),
X8L8V8U8_FLAG = FLG(20),
Q8W8V8U8_FLAG = FLG(21),
V16U16_FLAG = FLG(22),
D16_FLAG = FLG(18),
D24X8_FLAG = FLG(19),
D24S8_FLAG = FLG(20),
D32_FLAG = FLG(21),
INTZ_FLAG = FLG(22),
W11V11U10_FLAG = FLG(23),
A2W10V10U10_FLAG = FLG(24),
UYVY_FLAG = FLG(25),

View File

@ -296,9 +296,6 @@ rebuild_bitplanes() {
// Find the color and depth textures. Either may be present,
// or neither.
//
// NOTE: Currently, depth-stencil textures are not implemented,
// but since it's coming soon, we're structuring for it.
int color_tex_index = -1;
int depth_tex_index = -1;
@ -315,6 +312,11 @@ rebuild_bitplanes() {
color_tex_index = i;
break;
case RTP_depth:
case RTP_depth_stencil:
depth_tex_index = i;
break;
case RTP_aux_rgba_0:
case RTP_aux_rgba_1:
case RTP_aux_rgba_2:

View File

@ -890,11 +890,11 @@ void Init_D3DFORMAT_map() {
INSERT_ELEM(L8);
INSERT_ELEM(A8L8);
INSERT_ELEM(A4L4);
INSERT_ELEM(V8U8);
INSERT_ELEM(L6V5U5);
INSERT_ELEM(X8L8V8U8);
INSERT_ELEM(Q8W8V8U8);
INSERT_ELEM(V16U16);
INSERT_ELEM(D16);
INSERT_ELEM(D24X8);
INSERT_ELEM(D24S8);
INSERT_ELEM(D32);
g_D3DFORMATmap[INTZ_FLAG] = (D3DFORMAT)MAKEFOURCC('I', 'N', 'T', 'Z');
// NOT IN DX9
// INSERT_ELEM(W11V11U10);
INSERT_ELEM(A2W10V10U10);