00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "dxTextureContext8.h"
00016 #include "config_dxgsg8.h"
00017 #include "dxGraphicsStateGuardian8.h"
00018 #include "pStatTimer.h"
00019 #include "dxgsg8base.h"
00020 #include "bamCache.h"
00021 #include "graphicsEngine.h"
00022
00023 #include <assert.h>
00024 #include <time.h>
00025
00026 TypeHandle DXTextureContext8::_type_handle;
00027
00028 static const DWORD g_LowByteMask = 0x000000FF;
00029
00030
00031
00032
00033
00034
00035 DXTextureContext8::
00036 DXTextureContext8(PreparedGraphicsObjects *pgo, Texture *tex, int view) :
00037 TextureContext(pgo, tex, view) {
00038
00039 if (dxgsg8_cat.is_spam()) {
00040 dxgsg8_cat.spam()
00041 << "Creating DX texture [" << tex->get_name() << "], minfilter(" << tex->get_minfilter() << "), magfilter(" << tex->get_magfilter() << "), anisodeg(" << tex->get_anisotropic_degree() << ")\n";
00042 }
00043
00044 _d3d_texture = NULL;
00045 _d3d_2d_texture = NULL;
00046 _d3d_volume_texture = NULL;
00047 _d3d_cube_texture = NULL;
00048 _has_mipmaps = false;
00049 }
00050
00051
00052
00053
00054
00055
00056 DXTextureContext8::
00057 ~DXTextureContext8() {
00058 delete_texture();
00059 }
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 void DXTextureContext8::
00077 evict_lru() {
00078 if (get_texture()->get_render_to_texture()) {
00079
00080 mark_used_lru();
00081 return;
00082 }
00083
00084 dequeue_lru();
00085 delete_texture();
00086 update_data_size_bytes(0);
00087 mark_unloaded();
00088 }
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 bool DXTextureContext8::
00101 create_texture(DXScreenData &scrn) {
00102 HRESULT hr;
00103 int num_alpha_bits;
00104 D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN;
00105 bool needs_luminance = false;
00106 bool compress_texture = false;
00107
00108 Texture *tex = get_texture();
00109 nassertr(IS_VALID_PTR(tex), false);
00110
00111 delete_texture();
00112
00113 #ifdef DO_PSTATS
00114 update_data_size_bytes(tex->estimate_texture_memory());
00115 #endif // DO_PSTATS
00116
00117
00118 DWORD target_bpp = get_bits_per_pixel(tex->get_format(), &num_alpha_bits);
00119 DWORD num_color_channels = tex->get_num_components();
00120
00121
00122
00123 DWORD orig_width = (DWORD)tex->get_x_size();
00124 DWORD orig_height = (DWORD)tex->get_y_size();
00125 DWORD orig_depth = (DWORD)tex->get_z_size();
00126
00127 if ((tex->get_format() == Texture::F_luminance_alpha)||
00128 (tex->get_format() == Texture::F_luminance_alphamask) ||
00129 (tex->get_format() == Texture::F_luminance)) {
00130 needs_luminance = true;
00131 }
00132
00133 if (num_alpha_bits > 0) {
00134 if (num_color_channels == 3) {
00135 dxgsg8_cat.error()
00136 << "texture " << tex->get_name()
00137 << " has no inherent alpha channel, but alpha format is requested!\n";
00138 }
00139 }
00140
00141 _d3d_format = D3DFMT_UNKNOWN;
00142
00143
00144
00145 switch (num_color_channels) {
00146 case 1:
00147 if (num_alpha_bits > 0) {
00148 _d3d_format = D3DFMT_A8;
00149 } else if (needs_luminance) {
00150 _d3d_format = D3DFMT_L8;
00151 }
00152 break;
00153 case 2:
00154 nassertr(needs_luminance && (num_alpha_bits > 0), false);
00155 _d3d_format = D3DFMT_A8L8;
00156 break;
00157 case 3:
00158 _d3d_format = D3DFMT_R8G8B8;
00159 break;
00160 case 4:
00161 _d3d_format = D3DFMT_A8R8G8B8;
00162 break;
00163 }
00164
00165
00166 bool texture_wants_compressed = false;
00167 Texture::CompressionMode compression_mode = tex->get_ram_image_compression();
00168 bool texture_stored_compressed = compression_mode != Texture::CM_off;
00169
00170 if (texture_stored_compressed) {
00171 texture_wants_compressed = true;
00172 }
00173 else {
00174 if (tex->get_compression() == Texture::CM_off) {
00175
00176 }
00177 else {
00178 if (tex->get_compression() == Texture::CM_default) {
00179
00180 if (compressed_textures) {
00181 texture_wants_compressed = true;
00182 }
00183 }
00184 else {
00185 texture_wants_compressed = true;
00186 }
00187 }
00188 }
00189
00190 switch (tex->get_texture_type()) {
00191 case Texture::TT_1d_texture:
00192 case Texture::TT_2d_texture:
00193 case Texture::TT_cube_map:
00194
00195
00196 if (tex->get_render_to_texture() == false &&
00197 orig_width >= 4 && orig_height >= 4) {
00198 if (texture_wants_compressed){
00199 compress_texture = true;
00200 }
00201 }
00202 break;
00203 case Texture::TT_3d_texture:
00204
00205 break;
00206 }
00207
00208
00209 nassertr(_d3d_format != D3DFMT_UNKNOWN, false);
00210
00211 DWORD target_width = orig_width;
00212 DWORD target_height = orig_height;
00213 DWORD target_depth = orig_depth;
00214
00215 DWORD filter_caps;
00216
00217 switch (tex->get_texture_type()) {
00218 case Texture::TT_1d_texture:
00219 case Texture::TT_2d_texture:
00220 filter_caps = scrn._d3dcaps.TextureFilterCaps;
00221
00222 if (target_width > scrn._d3dcaps.MaxTextureWidth) {
00223 target_width = scrn._d3dcaps.MaxTextureWidth;
00224 }
00225 if (target_height > scrn._d3dcaps.MaxTextureHeight) {
00226 target_height = scrn._d3dcaps.MaxTextureHeight;
00227 }
00228
00229 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_POW2) {
00230 if (!ISPOW2(target_width)) {
00231 target_width = down_to_power_2(target_width);
00232 }
00233 if (!ISPOW2(target_height)) {
00234 target_height = down_to_power_2(target_height);
00235 }
00236 }
00237 break;
00238
00239 case Texture::TT_3d_texture:
00240 if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0) {
00241 dxgsg8_cat.warning()
00242 << "3-d textures are not supported by this graphics driver.\n";
00243 return false;
00244 }
00245
00246 filter_caps = scrn._d3dcaps.VolumeTextureFilterCaps;
00247
00248 if (target_width > scrn._d3dcaps.MaxVolumeExtent) {
00249 target_width = scrn._d3dcaps.MaxVolumeExtent;
00250 }
00251 if (target_height > scrn._d3dcaps.MaxVolumeExtent) {
00252 target_height = scrn._d3dcaps.MaxVolumeExtent;
00253 }
00254 if (target_depth > scrn._d3dcaps.MaxVolumeExtent) {
00255 target_depth = scrn._d3dcaps.MaxVolumeExtent;
00256 }
00257
00258 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2) {
00259 if (!ISPOW2(target_width)) {
00260 target_width = down_to_power_2(target_width);
00261 }
00262 if (!ISPOW2(target_height)) {
00263 target_height = down_to_power_2(target_height);
00264 }
00265 if (!ISPOW2(target_depth)) {
00266 target_depth = down_to_power_2(target_depth);
00267 }
00268 }
00269 break;
00270
00271 case Texture::TT_cube_map:
00272 if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) == 0) {
00273 dxgsg8_cat.warning()
00274 << "Cube map textures are not supported by this graphics driver.\n";
00275 return false;
00276 }
00277
00278 filter_caps = scrn._d3dcaps.CubeTextureFilterCaps;
00279
00280 if (target_width > scrn._d3dcaps.MaxTextureWidth) {
00281 target_width = scrn._d3dcaps.MaxTextureWidth;
00282 }
00283
00284 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) {
00285 if (!ISPOW2(target_width)) {
00286 target_width = down_to_power_2(target_width);
00287 }
00288 }
00289
00290 target_height = target_width;
00291 break;
00292 }
00293
00294
00295 if ((target_width != target_height) &&
00296 (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0) {
00297
00298
00299 int i, width_exp, height_exp;
00300 for (i = target_width, width_exp = 0; i > 1; width_exp++, i >>= 1) {
00301 }
00302 for (i = target_height, height_exp = 0; i > 1; height_exp++, i >>= 1) {
00303 }
00304 target_height = target_width = 1<<((width_exp+height_exp)>>1);
00305 }
00306
00307 bool shrink_original = false;
00308
00309 if (orig_width != target_width || orig_height != target_height ||
00310 orig_depth != target_depth) {
00311 if (tex->get_texture_type() == Texture::TT_3d_texture) {
00312 dxgsg8_cat.info()
00313 << "Reducing size of " << tex->get_name()
00314 << " from " << orig_width << "x" << orig_height << "x" << orig_depth
00315 << " to " << target_width << "x" << target_height
00316 << "x" << target_depth << "\n";
00317 } else {
00318 dxgsg8_cat.info()
00319 << "Reducing size of " << tex->get_name()
00320 << " from " << orig_width << "x" << orig_height
00321 << " to " << target_width << "x" << target_height << "\n";
00322 }
00323
00324 shrink_original = true;
00325 }
00326
00327 const char *error_message;
00328
00329 error_message = "create_texture failed: couldn't find compatible device Texture Pixel Format for input texture";
00330
00331 if (dxgsg8_cat.is_spam()) {
00332 dxgsg8_cat.spam()
00333 << "create_texture handling target bitdepth: " << target_bpp
00334 << " alphabits: " << num_alpha_bits << endl;
00335 }
00336
00337
00338
00339
00340
00341 #define CHECK_FOR_FMT(FMT) \
00342 if (scrn._supported_tex_formats_mask & FMT##_FLAG) { \
00343 target_pixel_format = D3DFMT_##FMT; \
00344 goto found_matching_format; }
00345
00346 if (texture_stored_compressed && compress_texture) {
00347
00348
00349
00350 switch (compression_mode){
00351 case Texture::CM_dxt1:
00352 CHECK_FOR_FMT(DXT1);
00353 break;
00354 case Texture::CM_dxt2:
00355 CHECK_FOR_FMT(DXT2);
00356 break;
00357 case Texture::CM_dxt3:
00358 CHECK_FOR_FMT(DXT3);
00359 break;
00360 case Texture::CM_dxt4:
00361 CHECK_FOR_FMT(DXT4);
00362 break;
00363 case Texture::CM_dxt5:
00364 CHECK_FOR_FMT(DXT5);
00365 break;
00366 }
00367
00368
00369 }
00370
00371 if (compress_texture) {
00372 if (num_alpha_bits <= 1) {
00373 CHECK_FOR_FMT(DXT1);
00374 } else if (num_alpha_bits <= 4) {
00375 CHECK_FOR_FMT(DXT3);
00376 } else {
00377 CHECK_FOR_FMT(DXT5);
00378 }
00379 }
00380
00381
00382
00383 if (texture_stored_compressed) {
00384 tex->get_uncompressed_ram_image();
00385 compression_mode = tex->get_ram_image_compression();
00386 texture_stored_compressed = compression_mode != Texture::CM_off;
00387 compress_texture = false;
00388 }
00389
00390
00391
00392 switch (target_bpp) {
00393
00394
00395
00396
00397
00398 case 32:
00399 if (!((num_color_channels == 3) || (num_color_channels == 4)))
00400 break;
00401
00402 CHECK_FOR_FMT(A8R8G8B8);
00403
00404 if (num_alpha_bits>0) {
00405 nassertr(num_color_channels == 4, false);
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421 if (num_alpha_bits == 1) {
00422 CHECK_FOR_FMT(A1R5G5B5);
00423 }
00424
00425
00426 CHECK_FOR_FMT(A4R4G4B4);
00427 CHECK_FOR_FMT(A1R5G5B5);
00428
00429
00430
00431 error_message = "create_texture failed: couldn't find compatible Tex DDPIXELFORMAT! no available 16 or 32-bit alpha formats!";
00432 } else {
00433
00434
00435 if (num_color_channels == 3) {
00436 CHECK_FOR_FMT(R5G6B5);
00437 CHECK_FOR_FMT(X1R5G5B5);
00438 } else {
00439 CHECK_FOR_FMT(R5G6B5);
00440 CHECK_FOR_FMT(X1R5G5B5);
00441 }
00442 }
00443 break;
00444
00445 case 24:
00446 nassertr(num_color_channels == 3, false);
00447
00448 CHECK_FOR_FMT(R8G8B8);
00449
00450
00451
00452
00453
00454 CHECK_FOR_FMT(X8R8G8B8);
00455 CHECK_FOR_FMT(A8R8G8B8);
00456
00457
00458 CHECK_FOR_FMT(R5G6B5);
00459 CHECK_FOR_FMT(X1R5G5B5);
00460 CHECK_FOR_FMT(A1R5G5B5);
00461 break;
00462
00463 case 16:
00464 if (needs_luminance) {
00465 nassertr(num_alpha_bits > 0, false);
00466 nassertr(num_color_channels == 2, false);
00467
00468 CHECK_FOR_FMT(A8L8);
00469 CHECK_FOR_FMT(A8R8G8B8);
00470
00471 if (num_alpha_bits == 1) {
00472 CHECK_FOR_FMT(A1R5G5B5);
00473 }
00474
00475
00476 CHECK_FOR_FMT(A4R4G4B4);
00477 CHECK_FOR_FMT(A1R5G5B5);
00478 } else {
00479 nassertr((num_color_channels == 3)||(num_color_channels == 4), false);
00480
00481
00482 switch(num_alpha_bits) {
00483 case 0:
00484 if (num_color_channels == 3) {
00485 CHECK_FOR_FMT(R5G6B5);
00486 CHECK_FOR_FMT(X1R5G5B5);
00487 } else {
00488 nassertr(num_color_channels == 4, false);
00489
00490 CHECK_FOR_FMT(R5G6B5);
00491 CHECK_FOR_FMT(X1R5G5B5);
00492 }
00493 break;
00494 case 1:
00495
00496
00497
00498
00499 nassertr(num_color_channels == 4, false);
00500 CHECK_FOR_FMT(X1R5G5B5);
00501 break;
00502 case 4:
00503
00504
00505 nassertr(num_color_channels == 4, false);
00506 CHECK_FOR_FMT(A4R4G4B4);
00507 break;
00508 default:
00509 nassertr(false, false);
00510 }
00511 }
00512 case 8:
00513 if (needs_luminance) {
00514
00515
00516 nassertr(num_color_channels == 1, false);
00517
00518
00519 CHECK_FOR_FMT(L8);
00520 CHECK_FOR_FMT(L8);
00521
00522 CHECK_FOR_FMT(R8G8B8);
00523 CHECK_FOR_FMT(X8R8G8B8);
00524
00525 CHECK_FOR_FMT(R5G6B5);
00526 CHECK_FOR_FMT(X1R5G5B5);
00527
00528 } else if (num_alpha_bits == 8) {
00529
00530
00531
00532
00533
00534
00535
00536 CHECK_FOR_FMT(A8L8);
00537 CHECK_FOR_FMT(A8R8G8B8);
00538 CHECK_FOR_FMT(A4R4G4B4);
00539 }
00540 break;
00541
00542 default:
00543 error_message = "create_texture failed: unhandled pixel bitdepth in DX loader";
00544 }
00545
00546
00547 dxgsg8_cat.error()
00548 << error_message << ": " << tex->get_name() << endl
00549 << "NumColorChannels: " << num_color_channels << "; NumAlphaBits: "
00550 << num_alpha_bits << "; targetbpp: " <<target_bpp
00551 << "; _supported_tex_formats_mask: 0x"
00552 << (void*)scrn._supported_tex_formats_mask
00553 << "; NeedLuminance: " << needs_luminance << endl;
00554 goto error_exit;
00555
00556
00557
00558 found_matching_format:
00559
00560
00561 if (tex->get_match_framebuffer_format()) {
00562
00563
00564
00565 IDirect3DSurface8 *render_target;
00566 hr = scrn._d3d_device->GetRenderTarget(&render_target);
00567 if (FAILED(hr)) {
00568 dxgsg8_cat.error()
00569 << "GetRenderTgt failed in create_texture: " << D3DERRORSTRING(hr);
00570 } else {
00571 D3DSURFACE_DESC surface_desc;
00572 hr = render_target->GetDesc(&surface_desc);
00573 if (FAILED(hr)) {
00574 dxgsg8_cat.error()
00575 << "GetDesc failed in create_texture: " << D3DERRORSTRING(hr);
00576 } else {
00577 if (target_pixel_format != surface_desc.Format) {
00578 if (dxgsg8_cat.is_debug()) {
00579 dxgsg8_cat.debug()
00580 << "Chose format " << D3DFormatStr(surface_desc.Format)
00581 << " instead of " << D3DFormatStr(target_pixel_format)
00582 << " for texture to match framebuffer.\n";
00583 }
00584 target_pixel_format = surface_desc.Format;
00585 }
00586 }
00587 SAFE_RELEASE(render_target);
00588 }
00589 }
00590
00591
00592
00593
00594 Texture::FilterType ft;
00595
00596 ft = tex->get_magfilter();
00597 if ((ft != Texture::FT_linear) && ft != Texture::FT_nearest) {
00598
00599 if (ft == Texture::FT_nearest_mipmap_nearest) {
00600 ft = Texture::FT_nearest;
00601 } else {
00602 ft = Texture::FT_linear;
00603 }
00604 }
00605
00606 if (ft == Texture::FT_linear &&
00607 (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) {
00608 ft = Texture::FT_nearest;
00609 }
00610 tex->set_magfilter(ft);
00611
00612
00613 ft = tex->get_minfilter();
00614 _has_mipmaps = false;
00615
00616 if (!dx_ignore_mipmaps) {
00617 switch(ft) {
00618 case Texture::FT_nearest_mipmap_nearest:
00619 case Texture::FT_linear_mipmap_nearest:
00620 case Texture::FT_nearest_mipmap_linear:
00621 case Texture::FT_linear_mipmap_linear:
00622 _has_mipmaps = true;
00623 }
00624
00625 if (dx_mipmap_everything) {
00626 _has_mipmaps = true;
00627 if (dxgsg8_cat.is_spam()) {
00628 if (ft != Texture::FT_linear_mipmap_linear) {
00629 dxgsg8_cat.spam()
00630 << "Forcing trilinear mipmapping on DX texture ["
00631 << tex->get_name() << "]\n";
00632 }
00633 }
00634 ft = Texture::FT_linear_mipmap_linear;
00635 tex->set_minfilter(ft);
00636 }
00637
00638 } else if ((ft == Texture::FT_nearest_mipmap_nearest) ||
00639 (ft == Texture::FT_nearest_mipmap_linear)) {
00640 ft = Texture::FT_nearest;
00641
00642 } else if ((ft == Texture::FT_linear_mipmap_nearest) ||
00643 (ft == Texture::FT_linear_mipmap_linear)) {
00644 ft = Texture::FT_linear;
00645 }
00646
00647 nassertr((filter_caps & D3DPTFILTERCAPS_MINFPOINT) != 0, false);
00648
00649 #define TRILINEAR_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MINFLINEAR)
00650
00651
00652 switch(ft) {
00653 case Texture::FT_linear_mipmap_linear:
00654 if ((filter_caps & TRILINEAR_MIPMAP_TEXFILTERCAPS) != TRILINEAR_MIPMAP_TEXFILTERCAPS) {
00655 if (filter_caps & D3DPTFILTERCAPS_MINFLINEAR) {
00656 ft = Texture::FT_linear_mipmap_nearest;
00657 } else {
00658
00659
00660 ft = Texture::FT_nearest_mipmap_nearest;
00661 }
00662 }
00663 break;
00664
00665 case Texture::FT_nearest_mipmap_linear:
00666
00667 if (!((filter_caps & D3DPTFILTERCAPS_MIPFPOINT) &&
00668 (filter_caps & D3DPTFILTERCAPS_MINFLINEAR))) {
00669 ft = Texture::FT_nearest_mipmap_nearest;
00670 }
00671 break;
00672
00673 case Texture::FT_linear_mipmap_nearest:
00674
00675 if (!(filter_caps & D3DPTFILTERCAPS_MIPFLINEAR)) {
00676 ft = Texture::FT_nearest_mipmap_nearest;
00677 }
00678 break;
00679
00680 case Texture::FT_linear:
00681 if (!(filter_caps & D3DPTFILTERCAPS_MINFLINEAR)) {
00682 ft = Texture::FT_nearest;
00683 }
00684 break;
00685 }
00686
00687 tex->set_minfilter(ft);
00688
00689 uint aniso_degree;
00690
00691 aniso_degree = 1;
00692 if (scrn._d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) {
00693 aniso_degree = tex->get_anisotropic_degree();
00694 if ((aniso_degree>scrn._d3dcaps.MaxAnisotropy) ||
00695 dx_force_anisotropic_filtering) {
00696 aniso_degree = scrn._d3dcaps.MaxAnisotropy;
00697 }
00698 }
00699 tex->set_anisotropic_degree(aniso_degree);
00700
00701 #ifdef _DEBUG
00702 dxgsg8_cat.spam()
00703 << "create_texture: setting aniso degree for " << tex->get_name()
00704 << " to: " << aniso_degree << endl;
00705 #endif
00706
00707 UINT mip_level_count;
00708
00709 if (_has_mipmaps) {
00710 tex->get_ram_image();
00711 mip_level_count = tex->get_num_loadable_ram_mipmap_images();
00712 if (mip_level_count < 2) {
00713
00714 mip_level_count = 0;
00715
00716 if (dxgsg8_cat.is_debug()) {
00717 dxgsg8_cat.debug()
00718 << "create_texture: generating mipmaps for " << tex->get_name()
00719 << endl;
00720 }
00721 }
00722 } else {
00723 mip_level_count = 1;
00724 }
00725
00726 DWORD usage;
00727 D3DPOOL pool;
00728
00729 usage = 0;
00730 if (tex->get_render_to_texture ()) {
00731
00732 pool = D3DPOOL_DEFAULT;
00733 if (support_render_texture && scrn._dxgsg8 -> get_supports_render_texture ( )) {
00734 usage |= D3DUSAGE_RENDERTARGET;
00735 }
00736 }
00737 else {
00738 pool = D3DPOOL_MANAGED;
00739 }
00740
00741 switch (tex->get_texture_type()) {
00742 case Texture::TT_1d_texture:
00743 case Texture::TT_2d_texture:
00744 hr = scrn._d3d_device->CreateTexture
00745 (target_width, target_height, mip_level_count, usage,
00746 target_pixel_format, pool, &_d3d_2d_texture);
00747 _d3d_texture = _d3d_2d_texture;
00748 break;
00749
00750 case Texture::TT_3d_texture:
00751 hr = scrn._d3d_device->CreateVolumeTexture
00752 (target_width, target_height, target_depth, mip_level_count, usage,
00753 target_pixel_format, pool, &_d3d_volume_texture);
00754 _d3d_texture = _d3d_volume_texture;
00755 break;
00756
00757 case Texture::TT_cube_map:
00758 hr = scrn._d3d_device->CreateCubeTexture
00759 (target_width, mip_level_count, usage,
00760 target_pixel_format, pool, &_d3d_cube_texture);
00761 _d3d_texture = _d3d_cube_texture;
00762 break;
00763 }
00764
00765 if (FAILED(hr)) {
00766 dxgsg8_cat.error()
00767 << "D3D create_texture failed!" << D3DERRORSTRING(hr);
00768 goto error_exit;
00769 }
00770
00771 if (dxgsg8_cat.is_debug()) {
00772 dxgsg8_cat.debug()
00773 << "create_texture: " << tex->get_name()
00774 << " converting panda equivalent of " << D3DFormatStr(_d3d_format)
00775 << " => " << D3DFormatStr(target_pixel_format) << endl;
00776 }
00777
00778 hr = fill_d3d_texture_pixels(scrn);
00779 if (FAILED(hr)) {
00780 goto error_exit;
00781 }
00782
00783 if (tex->get_post_load_store_cache()) {
00784 tex->set_post_load_store_cache(false);
00785
00786 if (extract_texture_data()) {
00787 if (tex->has_ram_image()) {
00788 BamCache *cache = BamCache::get_global_ptr();
00789 PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo");
00790 if (record != (BamCacheRecord *)NULL) {
00791 record->set_data(tex, tex);
00792 cache->store(record);
00793 }
00794 }
00795 }
00796 }
00797
00798 scrn._dxgsg8->get_engine()->texture_uploaded(tex);
00799 mark_loaded();
00800 return true;
00801
00802 error_exit:
00803
00804 RELEASE(_d3d_texture, dxgsg8, "texture", RELEASE_ONCE);
00805 _d3d_2d_texture = NULL;
00806 _d3d_volume_texture = NULL;
00807 _d3d_cube_texture = NULL;
00808 return false;
00809 }
00810
00811
00812
00813
00814
00815
00816 bool DXTextureContext8::
00817 create_simple_texture(DXScreenData &scrn) {
00818 nassertr(IS_VALID_PTR(get_texture()), false);
00819
00820 HRESULT hr;
00821
00822 delete_texture();
00823
00824 _d3d_format = D3DFMT_A8R8G8B8;
00825 D3DFORMAT target_pixel_format = D3DFMT_A8R8G8B8;
00826 DWORD target_bpp = 32;
00827 DWORD num_color_channels = 4;
00828
00829 DWORD target_width = (DWORD)get_texture()->get_simple_x_size();
00830 DWORD target_height = (DWORD)get_texture()->get_simple_y_size();
00831 DWORD mip_level_count = 1;
00832 DWORD usage = 0;
00833 D3DPOOL pool = D3DPOOL_MANAGED;
00834
00835 int data_size = target_width * target_height * 4;
00836
00837 hr = scrn._d3d_device->CreateTexture
00838 (target_width, target_height, mip_level_count, usage,
00839 target_pixel_format, pool, &_d3d_2d_texture);
00840 _d3d_texture = _d3d_2d_texture;
00841 if (FAILED(hr)) {
00842 dxgsg8_cat.error()
00843 << "D3D create_simple_texture failed!" << D3DERRORSTRING(hr);
00844 dxgsg8_cat.error()
00845 << " width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n";
00846
00847 goto error_exit;
00848 }
00849
00850 if (dxgsg8_cat.is_debug()) {
00851 dxgsg8_cat.debug()
00852 << "create_simple_texture: " << get_texture()->get_name()
00853 << "\n";
00854 }
00855
00856 {
00857 CPTA_uchar image = get_texture()->get_simple_ram_image();
00858
00859 hr = -1;
00860
00861
00862 IDirect3DSurface8 *surface = NULL;
00863 _d3d_2d_texture->GetSurfaceLevel(0, &surface);
00864
00865 RECT source_size;
00866 source_size.left = source_size.top = 0;
00867 source_size.right = target_width;
00868 source_size.bottom = target_height;
00869
00870 DWORD mip_filter = D3DX_FILTER_LINEAR;
00871
00872 hr = D3DXLoadSurfaceFromMemory
00873 (surface, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)image.p(),
00874 target_pixel_format, target_width * 4, (PALETTEENTRY*)NULL,
00875 &source_size, mip_filter, (D3DCOLOR)0x0);
00876
00877 RELEASE(surface, dxgsg8, "create_simple_texture Surface", RELEASE_ONCE);
00878 }
00879
00880 if (FAILED(hr)) {
00881 dxgsg8_cat.debug ()
00882 << "*** fill_d3d_texture_pixels failed ***: format "
00883 << target_pixel_format
00884 << "\n";
00885
00886 goto error_exit;
00887 }
00888
00889 mark_simple_loaded();
00890 return true;
00891
00892 error_exit:
00893 RELEASE(_d3d_texture, dxgsg8, "texture", RELEASE_ONCE);
00894 _d3d_2d_texture = NULL;
00895 _d3d_volume_texture = NULL;
00896 _d3d_cube_texture = NULL;
00897 return false;
00898 }
00899
00900
00901
00902
00903
00904
00905 void DXTextureContext8::
00906 delete_texture() {
00907 if (_d3d_texture == NULL) {
00908
00909 return;
00910 }
00911
00912 RELEASE(_d3d_texture, dxgsg8, "texture", RELEASE_ONCE);
00913 _d3d_2d_texture = NULL;
00914 _d3d_volume_texture = NULL;
00915 _d3d_cube_texture = NULL;
00916 }
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926 bool DXTextureContext8::
00927 extract_texture_data() {
00928 HRESULT hr;
00929
00930 Texture *tex = get_texture();
00931 if (tex->get_texture_type() != Texture::TT_2d_texture) {
00932 dxgsg8_cat.error()
00933 << "Not supported: extract_texture_data for " << tex->get_texture_type()
00934 << "\n";
00935 return false;
00936 }
00937 nassertr(IS_VALID_PTR(_d3d_2d_texture), false);
00938
00939 D3DSURFACE_DESC desc;
00940 hr = _d3d_2d_texture->GetLevelDesc(0, &desc);
00941 if (FAILED(hr)) {
00942 dxgsg8_cat.error()
00943 << "Texture::GetLevelDesc() failed!" << D3DERRORSTRING(hr);
00944 return false;
00945 }
00946
00947 int div = 1;
00948 Texture::Format format = Texture::F_rgba;
00949 Texture::CompressionMode compression = Texture::CM_off;
00950
00951 switch (desc.Format) {
00952 case D3DFMT_R8G8B8:
00953 format = Texture::F_rgb;
00954 break;
00955
00956 case D3DFMT_A8R8G8B8:
00957 case D3DFMT_X8R8G8B8:
00958 break;
00959
00960 case D3DFMT_L8:
00961 format = Texture::F_luminance;
00962 break;
00963
00964 case D3DFMT_A8L8:
00965 format = Texture::F_luminance_alpha;
00966 break;
00967
00968 case D3DFMT_DXT1:
00969 compression = Texture::CM_dxt1;
00970 div = 4;
00971 break;
00972 case D3DFMT_DXT2:
00973 compression = Texture::CM_dxt2;
00974 div = 4;
00975 break;
00976 case D3DFMT_DXT3:
00977 compression = Texture::CM_dxt3;
00978 div = 4;
00979 break;
00980 case D3DFMT_DXT4:
00981 compression = Texture::CM_dxt4;
00982 div = 4;
00983 break;
00984 case D3DFMT_DXT5:
00985 compression = Texture::CM_dxt5;
00986 div = 4;
00987 break;
00988
00989 default:
00990 dxgsg8_cat.error()
00991 << "Cannot extract texture data: unhandled surface format "
00992 << desc.Format << "\n";
00993 return false;
00994 }
00995
00996 int num_levels = _d3d_2d_texture->GetLevelCount();
00997
00998 tex->set_x_size(desc.Width);
00999 tex->set_y_size(desc.Height);
01000 tex->set_z_size(1);
01001 tex->set_component_type(Texture::T_unsigned_byte);
01002 tex->set_format(format);
01003 tex->clear_ram_image();
01004
01005 for (int n = 0; n < num_levels; ++n) {
01006 D3DLOCKED_RECT rect;
01007 hr = _d3d_2d_texture->LockRect(n, &rect, NULL, D3DLOCK_READONLY);
01008 if (FAILED(hr)) {
01009 dxgsg8_cat.error()
01010 << "Texture::LockRect() failed!" << D3DERRORSTRING(hr);
01011 return false;
01012 }
01013
01014 int x_size = tex->get_expected_mipmap_x_size(n);
01015 int y_size = tex->get_expected_mipmap_y_size(n);
01016 PTA_uchar image;
01017
01018 if (compression == Texture::CM_off) {
01019
01020 int pitch = x_size * tex->get_num_components() * tex->get_component_width();
01021 pitch = min(pitch, (int)rect.Pitch);
01022 int size = pitch * y_size;
01023 image = PTA_uchar::empty_array(size);
01024 if (pitch == rect.Pitch) {
01025
01026 memcpy(image.p(), rect.pBits, size);
01027 } else {
01028
01029
01030 unsigned char *dest = image.p();
01031 unsigned char *source = (unsigned char *)rect.pBits;
01032 for (int yi = 0; yi < y_size; ++yi) {
01033 memcpy(dest, source, pitch);
01034 dest += pitch;
01035 source += rect.Pitch;
01036 }
01037 }
01038
01039 } else {
01040
01041 int size = rect.Pitch * (y_size / div);
01042 image = PTA_uchar::empty_array(size);
01043 memcpy(image.p(), rect.pBits, size);
01044 }
01045
01046 _d3d_2d_texture->UnlockRect(n);
01047 if (n == 0) {
01048 tex->set_ram_image(image, compression);
01049 } else {
01050 tex->set_ram_mipmap_image(n, image);
01051 }
01052 }
01053
01054 return true;
01055 }
01056
01057
01058
01059
01060
01061
01062
01063 HRESULT DXTextureContext8::
01064 d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface8 *d3d_surface,
01065 bool inverted, Texture *result, int z) {
01066
01067
01068
01069 HRESULT hr;
01070 DWORD num_components = result->get_num_components();
01071
01072 nassertr(result->get_component_width() == sizeof(BYTE), E_FAIL);
01073 nassertr(result->get_component_type() == Texture::T_unsigned_byte, E_FAIL);
01074 nassertr((num_components == 3) || (num_components == 4), E_FAIL);
01075 nassertr(IS_VALID_PTR(d3d_surface), E_FAIL);
01076
01077 BYTE *buf = result->modify_ram_image();
01078 if (z >= 0) {
01079 nassertr(z < result->get_z_size(), E_FAIL);
01080 buf += z * result->get_expected_ram_page_size();
01081 }
01082
01083 if (IsBadWritePtr(d3d_surface, sizeof(DWORD))) {
01084 dxgsg8_cat.error()
01085 << "d3d_surface_to_texture failed: bad pD3DSurf ptr value ("
01086 << ((void*)d3d_surface) << ")\n";
01087 exit(1);
01088 }
01089
01090 DWORD x_window_offset, y_window_offset;
01091 DWORD copy_width, copy_height;
01092
01093 D3DLOCKED_RECT locked_rect;
01094 D3DSURFACE_DESC surface_desc;
01095
01096 hr = d3d_surface->GetDesc(&surface_desc);
01097
01098 x_window_offset = source_rect.left, y_window_offset = source_rect.top;
01099 copy_width = RECT_XSIZE(source_rect);
01100 copy_height = RECT_YSIZE(source_rect);
01101
01102
01103
01104
01105 if (!((copy_width == result->get_x_size()) && (copy_height <= (DWORD)result->get_y_size()))) {
01106 dxgsg8_cat.error()
01107 << "d3d_surface_to_texture, Texture size (" << result->get_x_size()
01108 << ", " << result->get_y_size()
01109 << ") too small to hold display surface ("
01110 << copy_width << ", " << copy_height << ")\n";
01111 nassertr(false, E_FAIL);
01112 return E_FAIL;
01113 }
01114
01115 hr = d3d_surface->LockRect(&locked_rect, (CONST RECT*)NULL, (D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE));
01116 if (FAILED(hr)) {
01117 dxgsg8_cat.error()
01118 << "d3d_surface_to_texture LockRect() failed!" << D3DERRORSTRING(hr);
01119 return hr;
01120 }
01121
01122
01123 nassertr((surface_desc.Format == D3DFMT_A8R8G8B8) ||
01124 (surface_desc.Format == D3DFMT_X8R8G8B8) ||
01125 (surface_desc.Format == D3DFMT_R8G8B8) ||
01126 (surface_desc.Format == D3DFMT_R5G6B5) ||
01127 (surface_desc.Format == D3DFMT_X1R5G5B5) ||
01128 (surface_desc.Format == D3DFMT_A1R5G5B5) ||
01129 (surface_desc.Format == D3DFMT_A4R4G4B4), E_FAIL);
01130
01131
01132
01133 int byte_pitch = locked_rect.Pitch;
01134 BYTE *surface_bytes = (BYTE *)locked_rect.pBits;
01135
01136 if (inverted) {
01137 surface_bytes += byte_pitch * (y_window_offset + copy_height - 1);
01138 byte_pitch = -byte_pitch;
01139 } else {
01140 surface_bytes += byte_pitch * y_window_offset;
01141 }
01142
01143
01144
01145
01146 if (dxgsg8_cat.is_debug()) {
01147 dxgsg8_cat.debug()
01148 << "d3d_surface_to_texture converting "
01149 << D3DFormatStr(surface_desc.Format)
01150 << " DDSurf to " << num_components << "-channel panda Texture\n";
01151 }
01152
01153 DWORD *dest_word = (DWORD *)buf;
01154 BYTE *dest_byte = (BYTE *)buf;
01155
01156 switch(surface_desc.Format) {
01157 case D3DFMT_A8R8G8B8:
01158 case D3DFMT_X8R8G8B8: {
01159 if (num_components == 4) {
01160 DWORD *source_word;
01161 BYTE *dest_line = (BYTE*)dest_word;
01162
01163 for (DWORD y = 0; y < copy_height; y++) {
01164 source_word = ((DWORD*)surface_bytes) + x_window_offset;
01165 memcpy(dest_line, source_word, byte_pitch);
01166 dest_line += byte_pitch;
01167 surface_bytes += byte_pitch;
01168 }
01169 } else {
01170
01171 DWORD *source_word;
01172 for (DWORD y = 0; y < copy_height; y++) {
01173 source_word = ((DWORD*)surface_bytes) + x_window_offset;
01174
01175 for (DWORD x = 0; x < copy_width; x++) {
01176 BYTE r, g, b;
01177 DWORD pixel = *source_word;
01178
01179 r = (BYTE)((pixel>>16) & g_LowByteMask);
01180 g = (BYTE)((pixel>> 8) & g_LowByteMask);
01181 b = (BYTE)((pixel ) & g_LowByteMask);
01182
01183 *dest_byte++ = b;
01184 *dest_byte++ = g;
01185 *dest_byte++ = r;
01186 source_word++;
01187 }
01188 surface_bytes += byte_pitch;
01189 }
01190 }
01191 break;
01192 }
01193
01194 case D3DFMT_R8G8B8: {
01195 BYTE *source_byte;
01196
01197 if (num_components == 4) {
01198 for (DWORD y = 0; y < copy_height; y++) {
01199 source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE);
01200 for (DWORD x = 0; x < copy_width; x++) {
01201 DWORD r, g, b;
01202
01203 b = *source_byte++;
01204 g = *source_byte++;
01205 r = *source_byte++;
01206
01207 *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b;
01208 dest_word++;
01209 }
01210 surface_bytes += byte_pitch;
01211 }
01212 } else {
01213
01214 for (DWORD y = 0; y < copy_height; y++) {
01215 source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE);
01216 memcpy(dest_byte, source_byte, byte_pitch);
01217 dest_byte += byte_pitch;
01218 surface_bytes += byte_pitch;
01219 }
01220 }
01221 break;
01222 }
01223
01224 case D3DFMT_R5G6B5:
01225 case D3DFMT_X1R5G5B5:
01226 case D3DFMT_A1R5G5B5:
01227 case D3DFMT_A4R4G4B4: {
01228 WORD *source_word;
01229
01230
01231 BYTE redshift, greenshift, blueshift;
01232 DWORD redmask, greenmask, bluemask;
01233
01234 if (surface_desc.Format == D3DFMT_R5G6B5) {
01235 redshift = (11-3);
01236 redmask = 0xF800;
01237 greenmask = 0x07E0;
01238 greenshift = (5-2);
01239 bluemask = 0x001F;
01240 blueshift = 3;
01241 } else if (surface_desc.Format == D3DFMT_A4R4G4B4) {
01242 redmask = 0x0F00;
01243 redshift = 4;
01244 greenmask = 0x00F0;
01245 greenshift = 0;
01246 bluemask = 0x000F;
01247 blueshift = 4;
01248 } else {
01249 redmask = 0x7C00;
01250 redshift = (10-3);
01251 greenmask = 0x03E0;
01252 greenshift = (5-3);
01253 bluemask = 0x001F;
01254 blueshift = 3;
01255 }
01256
01257 if (num_components == 4) {
01258
01259
01260
01261
01262
01263
01264 for (DWORD y = 0; y < copy_height; y++) {
01265 source_word = ((WORD*)surface_bytes) + x_window_offset;
01266 for (DWORD x = 0; x < copy_width; x++) {
01267 WORD pixel = *source_word;
01268 BYTE r, g, b;
01269
01270 b = (pixel & bluemask) << blueshift;
01271 g = (pixel & greenmask) >> greenshift;
01272 r = (pixel & redmask) >> redshift;
01273
01274
01275
01276 *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b;
01277 source_word++;
01278 dest_word++;
01279 }
01280 surface_bytes += byte_pitch;
01281 }
01282 } else {
01283
01284 for (DWORD y = 0; y < copy_height; y++) {
01285 source_word = ((WORD*)surface_bytes) + x_window_offset;
01286 for (DWORD x = 0; x < copy_width; x++) {
01287 WORD pixel = *source_word;
01288 BYTE r, g, b;
01289
01290 b = (pixel & bluemask) << blueshift;
01291 g = (pixel & greenmask) >> greenshift;
01292 r = (pixel & redmask) >> redshift;
01293
01294 *dest_byte++ = b;
01295 *dest_byte++ = g;
01296 *dest_byte++ = r;
01297
01298 source_word++;
01299 }
01300 surface_bytes += byte_pitch;
01301 }
01302 }
01303 break;
01304 }
01305
01306 default:
01307 dxgsg8_cat.error()
01308 << "d3d_surface_to_texture: unsupported D3DFORMAT!\n";
01309 }
01310
01311 d3d_surface->UnlockRect();
01312 return S_OK;
01313 }
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323 static UINT calculate_row_byte_length (int width, int num_color_channels, D3DFORMAT tex_format)
01324 {
01325 UINT source_row_byte_length = 0;
01326
01327
01328 switch (tex_format) {
01329 case D3DFMT_DXT1:
01330
01331
01332 source_row_byte_length = max(1,width / 4)*8;
01333 break;
01334 case D3DFMT_DXT2:
01335 case D3DFMT_DXT3:
01336 case D3DFMT_DXT4:
01337 case D3DFMT_DXT5:
01338
01339 source_row_byte_length = max(1,width / 4)*16;
01340 break;
01341 default:
01342
01343 source_row_byte_length = width*num_color_channels;
01344 break;
01345 }
01346 return source_row_byte_length;
01347 }
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357 HRESULT DXTextureContext8::fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_format)
01358 {
01359
01360
01361 IDirect3DSurface8 *mip_surface = NULL;
01362 bool using_temp_buffer = false;
01363 HRESULT hr = E_FAIL;
01364 CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level);
01365 nassertr(!image.is_null(), E_FAIL);
01366 BYTE *pixels = (BYTE*) image.p();
01367 DWORD width = (DWORD) get_texture()->get_expected_mipmap_x_size(mip_level);
01368 DWORD height = (DWORD) get_texture()->get_expected_mipmap_y_size(mip_level);
01369 int component_width = get_texture()->get_component_width();
01370
01371 pixels += depth_index * get_texture()->get_expected_ram_mipmap_page_size(mip_level);
01372
01373 if (get_texture()->get_texture_type() == Texture::TT_cube_map) {
01374 nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
01375 hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)depth_index, mip_level, &mip_surface);
01376 } else {
01377 nassertr(IS_VALID_PTR(_d3d_2d_texture), E_FAIL);
01378 hr = _d3d_2d_texture->GetSurfaceLevel(mip_level, &mip_surface);
01379 }
01380
01381 if (FAILED(hr)) {
01382 dxgsg8_cat.error()
01383 << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
01384 << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
01385 return E_FAIL;
01386 }
01387
01388 RECT source_size;
01389 source_size.left = source_size.top = 0;
01390 source_size.right = width;
01391 source_size.bottom = height;
01392
01393 UINT source_row_byte_length = calculate_row_byte_length(width, get_texture()->get_num_components(), source_format);
01394
01395 DWORD mip_filter;
01396
01397
01398 mip_filter = D3DX_FILTER_LINEAR ;
01399
01400
01401
01402 if (_d3d_format == D3DFMT_A8) {
01403
01404 USHORT *temp_buffer = new USHORT[width * height];
01405 if (!IS_VALID_PTR(temp_buffer)) {
01406 dxgsg8_cat.error()
01407 << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n";
01408 goto exit_FillMipmapSurf;
01409 }
01410 using_temp_buffer = true;
01411
01412 USHORT *out_pixels = temp_buffer;
01413 BYTE *source_pixels = pixels + component_width - 1;
01414 for (UINT y = 0; y < height; y++) {
01415 for (UINT x = 0; x < width; x++, source_pixels += component_width, out_pixels++) {
01416
01417
01418
01419 *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
01420 }
01421 }
01422
01423 source_format = D3DFMT_A8L8;
01424 source_row_byte_length = width * sizeof(USHORT);
01425 pixels = (BYTE*)temp_buffer;
01426 }
01427 else if (component_width != 1) {
01428
01429
01430
01431
01432
01433 int num_components = get_texture()->get_num_components();
01434 int num_pixels = width * height * num_components;
01435 BYTE *temp_buffer = new BYTE[num_pixels];
01436 if (!IS_VALID_PTR(temp_buffer)) {
01437 dxgsg8_cat.error() << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n";
01438 goto exit_FillMipmapSurf;
01439 }
01440 using_temp_buffer = true;
01441
01442 BYTE *source_pixels = pixels + component_width - 1;
01443 for (int i = 0; i < num_pixels; i++) {
01444 temp_buffer[i] = *source_pixels;
01445 source_pixels += component_width;
01446 }
01447 pixels = (BYTE*)temp_buffer;
01448 }
01449
01450
01451 #ifdef DO_PSTATS
01452 GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_row_byte_length * height);
01453 #endif
01454 hr = D3DXLoadSurfaceFromMemory
01455 (mip_surface, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)pixels,
01456 source_format, source_row_byte_length, (PALETTEENTRY*)NULL,
01457 &source_size, mip_filter, (D3DCOLOR)0x0);
01458 if (FAILED(hr)) {
01459 dxgsg8_cat.error()
01460 << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
01461 << ", mip_level " << mip_level
01462 << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
01463 }
01464
01465 exit_FillMipmapSurf:
01466 if (using_temp_buffer) {
01467 SAFE_DELETE_ARRAY(pixels);
01468 }
01469
01470 RELEASE(mip_surface, dxgsg8, "FillDDTextureMipmapPixels MipSurface texture ptr", RELEASE_ONCE);
01471 return hr;
01472 }
01473
01474
01475
01476
01477
01478
01479 HRESULT DXTextureContext8::
01480 fill_d3d_texture_pixels(DXScreenData &scrn) {
01481 Texture *tex = get_texture();
01482 nassertr(IS_VALID_PTR(tex), E_FAIL);
01483 if (tex->get_texture_type() == Texture::TT_3d_texture) {
01484 return fill_d3d_volume_texture_pixels(scrn);
01485 }
01486
01487 HRESULT hr = E_FAIL;
01488 nassertr(IS_VALID_PTR(tex), E_FAIL);
01489
01490 CPTA_uchar image;
01491 if (scrn._dxgsg8->get_supports_compressed_texture()) {
01492 image = tex->get_ram_image();
01493 } else {
01494 image = tex->get_uncompressed_ram_image();
01495 }
01496
01497 Texture::CompressionMode image_compression;
01498 if (image.is_null()) {
01499 image_compression = Texture::CM_off;
01500 } else {
01501 image_compression = tex->get_ram_image_compression();
01502 }
01503
01504 if (!scrn._dxgsg8->get_supports_compressed_texture_format(image_compression)) {
01505 image = tex->get_uncompressed_ram_image();
01506 image_compression = Texture::CM_off;
01507 }
01508 if (image.is_null()) {
01509
01510
01511
01512 return S_OK;
01513 }
01514 nassertr(IS_VALID_PTR((BYTE*)image.p()), E_FAIL);
01515 nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
01516
01517 PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
01518
01519 DWORD orig_depth = (DWORD) tex->get_z_size();
01520 D3DFORMAT source_format = _d3d_format;
01521
01522
01523 switch (image_compression) {
01524 case Texture::CM_dxt1:
01525 source_format = D3DFMT_DXT1;
01526 break;
01527 case Texture::CM_dxt2:
01528 source_format = D3DFMT_DXT2;
01529 break;
01530 case Texture::CM_dxt3:
01531 source_format = D3DFMT_DXT3;
01532 break;
01533 case Texture::CM_dxt4:
01534 source_format = D3DFMT_DXT4;
01535 break;
01536 case Texture::CM_dxt5:
01537 source_format = D3DFMT_DXT5;
01538 break;
01539 default:
01540
01541 break;
01542 }
01543
01544 for (unsigned int di = 0; di < orig_depth; di++) {
01545
01546
01547 hr = fill_d3d_texture_mipmap_pixels(0, di, source_format);
01548 if (FAILED(hr)) {
01549 return hr;
01550 }
01551
01552 if (_has_mipmaps) {
01553
01554 int miplevel_count = _d3d_2d_texture->GetLevelCount();
01555 if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
01556 dxgsg8_cat.debug()
01557 << "Using pre-calculated mipmap levels for texture " << tex->get_name() << "\n";
01558
01559 for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) {
01560 hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format);
01561 if (FAILED(hr)) {
01562 return hr;
01563 }
01564 }
01565 }
01566 else {
01567
01568
01569 DWORD mip_filter_flags;
01570 if (!dx_use_triangle_mipgen_filter) {
01571 mip_filter_flags = D3DX_FILTER_BOX;
01572 } else {
01573 mip_filter_flags = D3DX_FILTER_TRIANGLE;
01574 }
01575
01576
01577 hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0,
01578 mip_filter_flags);
01579
01580 if (FAILED(hr)) {
01581 dxgsg8_cat.error()
01582 << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
01583 << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
01584 }
01585 }
01586 }
01587 }
01588
01589 return hr;
01590 }
01591
01592
01593
01594
01595
01596
01597 HRESULT DXTextureContext8::
01598 fill_d3d_volume_texture_pixels(DXScreenData &scrn) {
01599 Texture *tex = get_texture();
01600 HRESULT hr = E_FAIL;
01601 nassertr(IS_VALID_PTR(tex), E_FAIL);
01602
01603 CPTA_uchar image;
01604 if (scrn._dxgsg8->get_supports_compressed_texture()) {
01605 image = tex->get_ram_image();
01606 } else {
01607 image = tex->get_uncompressed_ram_image();
01608 }
01609
01610 Texture::CompressionMode image_compression;
01611 if (image.is_null()) {
01612 image_compression = Texture::CM_off;
01613 } else {
01614 image_compression = tex->get_ram_image_compression();
01615 }
01616
01617 if (!scrn._dxgsg8->get_supports_compressed_texture_format(image_compression) ||
01618 tex->get_x_size() < 4 || tex->get_y_size() < 4) {
01619
01620
01621
01622
01623 image = tex->get_uncompressed_ram_image();
01624 image_compression = Texture::CM_off;
01625 }
01626
01627 if (image.is_null()) {
01628
01629
01630
01631 return S_OK;
01632 }
01633
01634 PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
01635
01636 nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
01637 nassertr(tex->get_texture_type() == Texture::TT_3d_texture, E_FAIL);
01638
01639 DWORD orig_width = (DWORD) tex->get_x_size();
01640 DWORD orig_height = (DWORD) tex->get_y_size();
01641 DWORD orig_depth = (DWORD) tex->get_z_size();
01642 DWORD num_color_channels = tex->get_num_components();
01643 D3DFORMAT source_format = _d3d_format;
01644 BYTE *image_pixels = (BYTE*)image.p();
01645 int component_width = tex->get_component_width();
01646
01647 nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
01648
01649 IDirect3DVolume8 *mip_level_0 = NULL;
01650 bool using_temp_buffer = false;
01651 BYTE *pixels = image_pixels;
01652
01653 nassertr(IS_VALID_PTR(_d3d_volume_texture), E_FAIL);
01654 hr = _d3d_volume_texture->GetVolumeLevel(0, &mip_level_0);
01655
01656 if (FAILED(hr)) {
01657 dxgsg8_cat.error()
01658 << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
01659 << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
01660 return E_FAIL;
01661 }
01662
01663 D3DBOX source_size;
01664 source_size.Left = source_size.Top = source_size.Front = 0;
01665 source_size.Right = orig_width;
01666 source_size.Bottom = orig_height;
01667 source_size.Back = orig_depth;
01668
01669 UINT source_row_byte_length = orig_width * num_color_channels;
01670 UINT source_page_byte_length = orig_height * source_row_byte_length;
01671
01672 DWORD level_0_filter, mip_filter_flags;
01673 using_temp_buffer = false;
01674
01675
01676
01677 level_0_filter = D3DX_FILTER_LINEAR ;
01678
01679
01680
01681 if (_d3d_format == D3DFMT_A8) {
01682
01683 USHORT *temp_buffer = new USHORT[orig_width * orig_height * orig_depth];
01684 if (!IS_VALID_PTR(temp_buffer)) {
01685 dxgsg8_cat.error()
01686 << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
01687 goto exit_FillDDSurf;
01688 }
01689 using_temp_buffer = true;
01690
01691 USHORT *out_pixels = temp_buffer;
01692 BYTE *source_pixels = pixels + component_width - 1;
01693 for (UINT z = 0; z < orig_depth; z++) {
01694 for (UINT y = 0; y < orig_height; y++) {
01695 for (UINT x = 0;
01696 x < orig_width;
01697 x++, source_pixels += component_width, out_pixels++) {
01698
01699
01700
01701 *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
01702 }
01703 }
01704 }
01705
01706 source_format = D3DFMT_A8L8;
01707 source_row_byte_length = orig_width * sizeof(USHORT);
01708 source_page_byte_length = orig_height * source_row_byte_length;
01709 pixels = (BYTE*)temp_buffer;
01710
01711 } else if (component_width != 1) {
01712
01713
01714
01715
01716
01717 int num_components = tex->get_num_components();
01718 int num_pixels = orig_width * orig_height * orig_depth * num_components;
01719 BYTE *temp_buffer = new BYTE[num_pixels];
01720 if (!IS_VALID_PTR(temp_buffer)) {
01721 dxgsg8_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
01722 goto exit_FillDDSurf;
01723 }
01724 using_temp_buffer = true;
01725
01726 BYTE *source_pixels = pixels + component_width - 1;
01727 for (int i = 0; i < num_pixels; i++) {
01728 temp_buffer[i] = *source_pixels;
01729 source_pixels += component_width;
01730 }
01731 pixels = (BYTE*)temp_buffer;
01732 }
01733
01734
01735
01736 #ifdef DO_PSTATS
01737 GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_page_byte_length * orig_depth);
01738 #endif
01739 hr = D3DXLoadVolumeFromMemory
01740 (mip_level_0, (PALETTEENTRY*)NULL, (D3DBOX*)NULL, (LPCVOID)pixels,
01741 source_format, source_row_byte_length, source_page_byte_length,
01742 (PALETTEENTRY*)NULL,
01743 &source_size, level_0_filter, (D3DCOLOR)0x0);
01744 if (FAILED(hr)) {
01745 dxgsg8_cat.error()
01746 << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
01747 << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr);
01748 goto exit_FillDDSurf;
01749 }
01750
01751 if (_has_mipmaps) {
01752 if (!dx_use_triangle_mipgen_filter) {
01753 mip_filter_flags = D3DX_FILTER_BOX;
01754 } else {
01755 mip_filter_flags = D3DX_FILTER_TRIANGLE;
01756 }
01757
01758
01759
01760 hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0,
01761 mip_filter_flags);
01762 if (FAILED(hr)) {
01763 dxgsg8_cat.error()
01764 << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
01765 << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
01766 goto exit_FillDDSurf;
01767 }
01768 }
01769
01770 exit_FillDDSurf:
01771 if (using_temp_buffer) {
01772 SAFE_DELETE_ARRAY(pixels);
01773 }
01774 RELEASE(mip_level_0, dxgsg8, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE);
01775 return hr;
01776 }
01777
01778
01779
01780
01781
01782
01783
01784
01785 int DXTextureContext8::
01786 down_to_power_2(int value) {
01787 int x = 1;
01788 while ((x << 1) <= value) {
01789 x = (x << 1);
01790 }
01791 return x;
01792 }
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802 unsigned int DXTextureContext8::
01803 get_bits_per_pixel(Texture::Format format, int *alphbits) {
01804 *alphbits = 0;
01805 switch(format) {
01806 case Texture::F_alpha:
01807 *alphbits = 8;
01808 case Texture::F_color_index:
01809 case Texture::F_red:
01810 case Texture::F_green:
01811 case Texture::F_blue:
01812 case Texture::F_rgb332:
01813 return 8;
01814 case Texture::F_luminance_alphamask:
01815 *alphbits = 1;
01816 return 16;
01817 case Texture::F_luminance_alpha:
01818 *alphbits = 8;
01819 return 16;
01820 case Texture::F_luminance:
01821 return 8;
01822 case Texture::F_rgba4:
01823 *alphbits = 4;
01824 return 16;
01825 case Texture::F_rgba5:
01826 *alphbits = 1;
01827 return 16;
01828 case Texture::F_depth_stencil:
01829 return 32;
01830 case Texture::F_rgb5:
01831 return 16;
01832 case Texture::F_rgb8:
01833 case Texture::F_rgb:
01834 return 24;
01835 case Texture::F_rgba8:
01836 case Texture::F_rgba:
01837 *alphbits = 8;
01838 return 32;
01839 case Texture::F_rgbm:
01840 *alphbits = 1;
01841 return 32;
01842 case Texture::F_rgb12:
01843 return 36;
01844 case Texture::F_rgba12:
01845 *alphbits = 12;
01846 return 48;
01847 }
01848 return 8;
01849 }