From fb317e3b7ae2365768db70130da1891dd86a22d1 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 26 Nov 2015 01:04:26 +0100 Subject: [PATCH] Implement depth textures and shadow mapping in DirectX 9 renderer (at long last) --- panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx | 12 + panda/src/dxgsg9/dxTextureContext9.cxx | 241 +++++++++++++----- panda/src/dxgsg9/dxgsg9base.h | 10 +- panda/src/dxgsg9/wdxGraphicsBuffer9.cxx | 8 +- panda/src/dxgsg9/wdxGraphicsPipe9.cxx | 10 +- 5 files changed, 207 insertions(+), 74 deletions(-) diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index c8d7833b4f..d3a16f00c2 100644 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -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) {\ diff --git a/panda/src/dxgsg9/dxTextureContext9.cxx b/panda/src/dxgsg9/dxTextureContext9.cxx index 1118655342..9c7421c0ff 100644 --- a/panda/src/dxgsg9/dxTextureContext9.cxx +++ b/panda/src/dxgsg9/dxTextureContext9.cxx @@ -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; diff --git a/panda/src/dxgsg9/dxgsg9base.h b/panda/src/dxgsg9/dxgsg9base.h index 9c00e41816..e781fe1f16 100644 --- a/panda/src/dxgsg9/dxgsg9base.h +++ b/panda/src/dxgsg9/dxgsg9base.h @@ -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), diff --git a/panda/src/dxgsg9/wdxGraphicsBuffer9.cxx b/panda/src/dxgsg9/wdxGraphicsBuffer9.cxx index f393987726..45c7f8a437 100644 --- a/panda/src/dxgsg9/wdxGraphicsBuffer9.cxx +++ b/panda/src/dxgsg9/wdxGraphicsBuffer9.cxx @@ -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: diff --git a/panda/src/dxgsg9/wdxGraphicsPipe9.cxx b/panda/src/dxgsg9/wdxGraphicsPipe9.cxx index 10aa6b8f00..4fe81dad5c 100644 --- a/panda/src/dxgsg9/wdxGraphicsPipe9.cxx +++ b/panda/src/dxgsg9/wdxGraphicsPipe9.cxx @@ -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);