Browse Source

Implement depth textures and shadow mapping in DirectX 9 renderer
(at long last)

rdb 10 years ago
parent
commit
fb317e3b7a

+ 12 - 0
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
   // check if compressed textures are supported
   #define CHECK_FOR_DXTVERSION(num) \
   #define CHECK_FOR_DXTVERSION(num) \
   if (_screen->_supported_tex_formats_mask & DXT##num##_FLAG) {\
   if (_screen->_supported_tex_formats_mask & DXT##num##_FLAG) {\

+ 176 - 57
panda/src/dxgsg9/dxTextureContext9.cxx

@@ -119,6 +119,8 @@ create_texture(DXScreenData &scrn) {
   int num_alpha_bits;     //  number of alpha bits in texture pixfmt
   int num_alpha_bits;     //  number of alpha bits in texture pixfmt
   D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN;
   D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN;
   bool needs_luminance = false;
   bool needs_luminance = false;
+  bool needs_depth = false;
+  bool needs_stencil = false;
   bool compress_texture = false;
   bool compress_texture = false;
 
 
   Texture *tex = get_texture();
   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 target_bpp = get_bits_per_pixel(tex->get_format(), &num_alpha_bits);
   DWORD num_color_channels = tex->get_num_components();
   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);
+  // figure out what 'D3DFMT' the Texture is in, so D3DXLoadSurfFromMem knows how to perform copy
+  switch (tex->get_format()) {
+  case Texture::F_depth_stencil:
+    _d3d_format = D3DFMT_D24S8;
+    needs_depth = true;
+    needs_stencil = true;
+    break;
 
 
-  //PRINT_REFCNT(dxgsg9, scrn._d3d9);
+  case Texture::F_depth_component:
+  case Texture::F_depth_component16:
+    _d3d_format = D3DFMT_D16;
+    needs_depth = true;
+    break;
 
 
-  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;
-  }
+  case Texture::F_depth_component24:
+    _d3d_format = D3DFMT_D24X8;
+    needs_depth = true;
+    break;
 
 
-  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";
-    }
-  }
+  case Texture::F_depth_component32:
+    _d3d_format = D3DFMT_D32;
+    needs_depth = true;
+    break;
 
 
-  _d3d_format = D3DFMT_UNKNOWN;
+  case Texture::F_luminance:
+  case Texture::F_sluminance:
+    _d3d_format = D3DFMT_L8;
+    needs_luminance = true;
+    break;
 
 
-  // figure out what 'D3DFMT' the Texture is in, so D3DXLoadSurfFromMem knows how to perform copy
+  case Texture::F_luminance_alpha:
+  case Texture::F_luminance_alphamask:
+  case Texture::F_sluminance_alpha:
+    _d3d_format = D3DFMT_A8L8;
+    needs_luminance = true;
+    break;
 
 
-  switch (num_color_channels) {
-  case 1:
+  default:
     if (num_alpha_bits > 0) {
     if (num_alpha_bits > 0) {
-      _d3d_format = D3DFMT_A8;
-    } else if (needs_luminance) {
-      _d3d_format = D3DFMT_L8;
+      if (num_color_channels == 3) {
+        dxgsg9_cat.error()
+          << "texture " << tex->get_name()
+          << " has no inherent alpha channel, but alpha format is requested!\n";
+      }
     }
     }
-    break;
-  case 2:
-    nassertr(needs_luminance && (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);
+    _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_width = orig_width;
   DWORD target_height = orig_height;
   DWORD target_height = orig_height;
@@ -447,6 +471,14 @@ create_texture(DXScreenData &scrn) {
     goto found_matching_format;
     goto found_matching_format;
 
 
   case 32:
   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)))
     if (!((num_color_channels == 3) || (num_color_channels == 4)))
       break; //bail
       break; //bail
 
 
@@ -494,25 +526,78 @@ create_texture(DXScreenData &scrn) {
     break;
     break;
 
 
   case 24:
   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 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);
+      // 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;
     break;
 
 
   case 16:
   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_alpha_bits > 0, false);
       nassertr(num_color_channels == 2, 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
     // Instead of creating a texture with the found format, we will
     // need to make one that exactly matches the framebuffer's
     // need to make one that exactly matches the framebuffer's
     // format.  Look up what that format is.
     // format.  Look up what that format is.
-    DWORD render_target_index;
     IDirect3DSurface9 *render_target;
     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)) {
     if (FAILED(hr)) {
       dxgsg9_cat.error()
       dxgsg9_cat.error()
         << "GetRenderTgt failed in create_texture: " << D3DERRORSTRING(hr);
         << "GetRenderTgt failed in create_texture: " << D3DERRORSTRING(hr);
@@ -628,7 +715,8 @@ create_texture(DXScreenData &scrn) {
         dxgsg9_cat.error()
         dxgsg9_cat.error()
           << "GetDesc failed in create_texture: " << D3DERRORSTRING(hr);
           << "GetDesc failed in create_texture: " << D3DERRORSTRING(hr);
       } else {
       } 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()) {
           if (dxgsg9_cat.is_debug()) {
             dxgsg9_cat.debug()
             dxgsg9_cat.debug()
               << "Chose format " << D3DFormatStr(surface_desc.Format)
               << "Chose format " << D3DFormatStr(surface_desc.Format)
@@ -786,10 +874,14 @@ create_texture(DXScreenData &scrn) {
     _is_render_target = true;
     _is_render_target = true;
 
 
     pool = D3DPOOL_DEFAULT;
     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 ()
     dxgsg9_cat.debug ()
       << "*** RENDER TO TEXTURE ***: format "
       << "*** RENDER TO TEXTURE ***: format "
@@ -1126,6 +1218,22 @@ extract_texture_data(DXScreenData &screen) {
     format = Texture::F_luminance_alpha;
     format = Texture::F_luminance_alpha;
     break;
     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:
   case D3DFMT_DXT1:
     compression = Texture::CM_dxt1;
     compression = Texture::CM_dxt1;
     div = 4;
     div = 4;
@@ -2159,8 +2267,12 @@ get_bits_per_pixel(Texture::Format format, int *alphbits) {
     *alphbits = 1;
     *alphbits = 1;
     return 16;
     return 16;
   case Texture::F_depth_component:
   case Texture::F_depth_component:
+  case Texture::F_depth_component16:
     return 16;
     return 16;
   case Texture::F_depth_stencil:
   case Texture::F_depth_stencil:
+  case Texture::F_depth_component24:
+    return 24;
+  case Texture::F_depth_component32:
     return 32;
     return 32;
   case Texture::F_rgb5:
   case Texture::F_rgb5:
     return 16;
     return 16;
@@ -2233,6 +2345,8 @@ d3d_format_to_bytes_per_pixel (D3DFORMAT format)
     case D3DFMT_A8L8:
     case D3DFMT_A8L8:
     case D3DFMT_A8R3G3B2:
     case D3DFMT_A8R3G3B2:
     case D3DFMT_X4R4G4B4:
     case D3DFMT_X4R4G4B4:
+    case D3DFMT_D16:
+    case (D3DFORMAT)MAKEFOURCC('D', 'F', '1', '6'):
       bytes_per_pixel = 2.0f;
       bytes_per_pixel = 2.0f;
       break;
       break;
 
 
@@ -2251,6 +2365,11 @@ d3d_format_to_bytes_per_pixel (D3DFORMAT format)
     case D3DFMT_X8B8G8R8:
     case D3DFMT_X8B8G8R8:
     case D3DFMT_G16R16:
     case D3DFMT_G16R16:
     case D3DFMT_A2R10G10B10:
     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;
       bytes_per_pixel = 4.0f;
       break;
       break;
 
 

+ 5 - 5
panda/src/dxgsg9/dxgsg9base.h

@@ -165,11 +165,11 @@ typedef enum {
     L8_FLAG =           FLG(15),
     L8_FLAG =           FLG(15),
     A8L8_FLAG =         FLG(16),
     A8L8_FLAG =         FLG(16),
     A4L4_FLAG =         FLG(17),
     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),
     W11V11U10_FLAG =    FLG(23),
     A2W10V10U10_FLAG =  FLG(24),
     A2W10V10U10_FLAG =  FLG(24),
     UYVY_FLAG =         FLG(25),
     UYVY_FLAG =         FLG(25),

+ 5 - 3
panda/src/dxgsg9/wdxGraphicsBuffer9.cxx

@@ -296,9 +296,6 @@ rebuild_bitplanes() {
 
 
   // Find the color and depth textures.  Either may be present,
   // Find the color and depth textures.  Either may be present,
   // or neither.
   // 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 color_tex_index = -1;
   int depth_tex_index = -1;
   int depth_tex_index = -1;
@@ -315,6 +312,11 @@ rebuild_bitplanes() {
           color_tex_index = i;
           color_tex_index = i;
           break;
           break;
 
 
+        case RTP_depth:
+        case RTP_depth_stencil:
+          depth_tex_index = i;
+          break;
+
         case RTP_aux_rgba_0:
         case RTP_aux_rgba_0:
         case RTP_aux_rgba_1:
         case RTP_aux_rgba_1:
         case RTP_aux_rgba_2:
         case RTP_aux_rgba_2:

+ 5 - 5
panda/src/dxgsg9/wdxGraphicsPipe9.cxx

@@ -890,11 +890,11 @@ void Init_D3DFORMAT_map() {
   INSERT_ELEM(L8);
   INSERT_ELEM(L8);
   INSERT_ELEM(A8L8);
   INSERT_ELEM(A8L8);
   INSERT_ELEM(A4L4);
   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
 //  NOT IN DX9
 //  INSERT_ELEM(W11V11U10);
 //  INSERT_ELEM(W11V11U10);
   INSERT_ELEM(A2W10V10U10);
   INSERT_ELEM(A2W10V10U10);