Panda3D
Loading...
Searching...
No Matches
dxTextureContext9.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file dxTextureContext9.cxx
10 * @author georges
11 * @date 2002-02-02
12 */
13
14#include "config_dxgsg9.h"
16#include "pStatTimer.h"
17#include "dxTextureContext9.h"
18#include "bamCache.h"
19#include "graphicsEngine.h"
20#include <d3dx9tex.h>
21#include <assert.h>
22#include <time.h>
23
24#define DEBUG_SURFACES false
25#define DEBUG_TEXTURES true
26
27using std::endl;
28using std::max;
29using std::min;
30
31TypeHandle DXTextureContext9::_type_handle;
32
33static const DWORD g_LowByteMask = 0x000000FF;
34
35/**
36 *
37 */
38DXTextureContext9::
39DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex, int view) :
40 TextureContext(pgo, tex, view) {
41
42 if (dxgsg9_cat.is_spam()) {
43 dxgsg9_cat.spam()
44 << "Creating DX texture [" << tex->get_name() << "], minfilter(" << tex->get_minfilter() << "), magfilter(" << tex->get_magfilter() << "), anisodeg(" << tex->get_anisotropic_degree() << ")\n";
45 }
46
47 _d3d_texture = nullptr;
48 _d3d_2d_texture = nullptr;
49 _d3d_volume_texture = nullptr;
50 _d3d_cube_texture = nullptr;
51 _has_mipmaps = false;
52 _is_render_target = false;
53 _managed = -1;
54}
55
56/**
57 *
58 */
59DXTextureContext9::
60~DXTextureContext9() {
62}
63
64/**
65 * Evicts the page from the LRU. Called internally when the LRU determines
66 * that it is full. May also be called externally when necessary to
67 * explicitly evict the page.
68 *
69 * It is legal for this method to either evict the page as requested, do
70 * nothing (in which case the eviction will be requested again at the next
71 * epoch), or requeue itself on the tail of the queue (in which case the
72 * eviction will be requested again much later).
73 */
75evict_lru() {
76 if (get_texture()->get_render_to_texture()) {
77 // Don't evict the result of render-to-texture.
79 return;
80 }
81 if (dxgsg9_cat.is_debug()) {
82 dxgsg9_cat.debug()
83 << "Evicting " << *get_texture() << "\n";
84 }
85
88
91}
92
93/**
94 * Use panda texture's pixelbuffer to create a texture for the specified
95 * device. This code gets the attributes of the texture from the bitmap,
96 * creates the texture, and then copies the bitmap into the texture. The
97 * return value is true if the texture is successfully created, false
98 * otherwise.
99 */
102
103 // check if the texture has already been created
104 if (_d3d_2d_texture || _d3d_cube_texture || _d3d_volume_texture) {
105 // texture already created, no need to create
106 return true;
107 }
108
109 HRESULT hr;
110 int num_alpha_bits; // number of alpha bits in texture pixfmt
111 D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN;
112 bool needs_luminance = false;
113 bool needs_depth = false;
114 bool needs_stencil = false;
115 bool compress_texture = false;
116
117 Texture *tex = get_texture();
118 nassertr(IS_VALID_PTR(tex), false);
119
120 // Ensure the ram image is loaded, if available.
121 tex->get_ram_image();
122
123 DWORD orig_width = (DWORD)tex->get_x_size();
124 DWORD orig_height = (DWORD)tex->get_y_size();
125 DWORD orig_depth = (DWORD)tex->get_z_size();
126
127 // check for texture compression
128 bool texture_wants_compressed = false;
129 Texture::CompressionMode compression_mode = tex->get_ram_image_compression();
130 bool texture_stored_compressed = compression_mode != Texture::CM_off;
131
132 if (texture_stored_compressed) {
133 texture_wants_compressed = true;
134 } else {
135 if (tex->get_compression() == Texture::CM_off) {
136 // no compression
137 } else {
138 if (tex->get_compression() == Texture::CM_default) {
139 // default = use "compressed-textures" config setting
140 if (compressed_textures) {
141 texture_wants_compressed = true;
142 }
143 } else {
144 texture_wants_compressed = true;
145 }
146 }
147 }
148
149 switch (tex->get_texture_type()) {
150 case Texture::TT_1d_texture:
151 case Texture::TT_2d_texture:
152 case Texture::TT_cube_map:
153 // no compression for render target textures, or very small textures
154 if (!tex->get_render_to_texture() &&
155 orig_width >= 4 && orig_height >= 4) {
156 if (texture_wants_compressed){
157 compress_texture = true;
158 }
159 }
160 break;
161 case Texture::TT_3d_texture:
162 // compression of 3d textures not supported by all video chips
163 break;
164 }
165
166 if (texture_stored_compressed && !compress_texture) {
167 // If we're going to need to reload the texture to get its uncompressed
168 // image, we'd better do so now, *before* we figure out the source format.
169 // We have to do this early, even though we're going to do it again in
170 // fill_d3d_texture_pixels(), because sometimes reloading the original ram
171 // image will change the texture's apparent pixel format (the compressed
172 // form may have a different format than the uncompressed form).
174
175 orig_width = (DWORD)tex->get_x_size();
176 orig_height = (DWORD)tex->get_y_size();
177 orig_depth = (DWORD)tex->get_z_size();
178 }
179
180 // bpp indicates requested fmt, not texture fmt
181 DWORD target_bpp = get_bits_per_pixel(tex->get_format(), &num_alpha_bits);
182 DWORD num_color_channels = tex->get_num_components();
183
184 // figure out what 'D3DFMT' the Texture is in, so D3DXLoadSurfFromMem knows
185 // how to perform copy
186 switch (tex->get_format()) {
187 case Texture::F_depth_stencil:
188 _d3d_format = D3DFMT_D24S8;
189 needs_depth = true;
190 needs_stencil = true;
191 break;
192
193 case Texture::F_depth_component:
194 case Texture::F_depth_component16:
195 _d3d_format = D3DFMT_D16;
196 needs_depth = true;
197 break;
198
199 case Texture::F_depth_component24:
200 _d3d_format = D3DFMT_D24X8;
201 needs_depth = true;
202 break;
203
204 case Texture::F_depth_component32:
205 _d3d_format = D3DFMT_D32;
206 needs_depth = true;
207 break;
208
209 case Texture::F_luminance:
210 case Texture::F_sluminance:
211 _d3d_format = D3DFMT_L8;
212 needs_luminance = true;
213 break;
214
215 case Texture::F_luminance_alpha:
216 case Texture::F_luminance_alphamask:
217 case Texture::F_sluminance_alpha:
218 _d3d_format = D3DFMT_A8L8;
219 needs_luminance = true;
220 break;
221
222 default:
223 if (num_alpha_bits > 0) {
224 if (num_color_channels == 3) {
225 dxgsg9_cat.error()
226 << "texture " << tex->get_name()
227 << " has no inherent alpha channel, but alpha format is requested!\n";
228 }
229 }
230
231 _d3d_format = D3DFMT_UNKNOWN;
232
233 switch (num_color_channels) {
234 case 1:
235 if (num_alpha_bits > 0) {
236 _d3d_format = D3DFMT_A8;
237 } else if (tex->get_component_type() == Texture::T_float) {
238 _d3d_format = D3DFMT_R32F;
239 } else {
240 _d3d_format = D3DFMT_L8;
241 }
242 break;
243 case 2:
244 _d3d_format = D3DFMT_A8L8;
245 break;
246 case 3:
247 _d3d_format = D3DFMT_R8G8B8;
248 break;
249 case 4:
250 if (tex->get_component_type() == Texture::T_float) {
251 _d3d_format = D3DFMT_A32B32G32R32F;
252 } else {
253 _d3d_format = D3DFMT_A8R8G8B8;
254 }
255 break;
256 }
257
258 // make sure we handled all the possible cases
259 nassertr(_d3d_format != D3DFMT_UNKNOWN, false);
260 }
261
262 DWORD target_width = orig_width;
263 DWORD target_height = orig_height;
264 DWORD target_depth = orig_depth;
265
266 DWORD filter_caps;
267
268 switch (tex->get_texture_type()) {
269 case Texture::TT_1d_texture:
270 case Texture::TT_2d_texture:
271 filter_caps = scrn._d3dcaps.TextureFilterCaps;
272
273 if (target_width > scrn._d3dcaps.MaxTextureWidth) {
274 target_width = scrn._d3dcaps.MaxTextureWidth;
275 }
276 if (target_height > scrn._d3dcaps.MaxTextureHeight) {
277 target_height = scrn._d3dcaps.MaxTextureHeight;
278 }
279
280 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_POW2) {
281 if (!ISPOW2(target_width)) {
282 target_width = down_to_power_2(target_width);
283 }
284 if (!ISPOW2(target_height)) {
285 target_height = down_to_power_2(target_height);
286 }
287 }
288 break;
289
290 case Texture::TT_3d_texture:
291 if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0) {
292 dxgsg9_cat.warning()
293 << "3-d textures are not supported by this graphics driver.\n";
294 return false;
295 }
296
297 filter_caps = scrn._d3dcaps.VolumeTextureFilterCaps;
298
299 if (target_width > scrn._d3dcaps.MaxVolumeExtent) {
300 target_width = scrn._d3dcaps.MaxVolumeExtent;
301 }
302 if (target_height > scrn._d3dcaps.MaxVolumeExtent) {
303 target_height = scrn._d3dcaps.MaxVolumeExtent;
304 }
305 if (target_depth > scrn._d3dcaps.MaxVolumeExtent) {
306 target_depth = scrn._d3dcaps.MaxVolumeExtent;
307 }
308
309 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2) {
310 if (!ISPOW2(target_width)) {
311 target_width = down_to_power_2(target_width);
312 }
313 if (!ISPOW2(target_height)) {
314 target_height = down_to_power_2(target_height);
315 }
316 if (!ISPOW2(target_depth)) {
317 target_depth = down_to_power_2(target_depth);
318 }
319 }
320 break;
321
322 case Texture::TT_cube_map:
323 if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) == 0) {
324 dxgsg9_cat.warning()
325 << "Cube map textures are not supported by this graphics driver.\n";
326 return false;
327 }
328
329 filter_caps = scrn._d3dcaps.CubeTextureFilterCaps;
330
331 if (target_width > scrn._d3dcaps.MaxTextureWidth) {
332 target_width = scrn._d3dcaps.MaxTextureWidth;
333 }
334
335 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) {
336 if (!ISPOW2(target_width)) {
337 target_width = down_to_power_2(target_width);
338 }
339 }
340
341 target_height = target_width;
342 break;
343 }
344
345 // checks for SQUARE reqmt (nvidia riva128 needs this)
346 if ((target_width != target_height) &&
347 (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0) {
348 // assume pow2 textures. sum exponents, divide by 2 rounding down to get
349 // sq size
350 int i, width_exp, height_exp;
351 for (i = target_width, width_exp = 0; i > 1; width_exp++, i >>= 1) {
352 }
353 for (i = target_height, height_exp = 0; i > 1; height_exp++, i >>= 1) {
354 }
355 target_height = target_width = 1<<((width_exp+height_exp)>>1);
356 }
357
358 bool shrink_original = false;
359
360 if (orig_width != target_width || orig_height != target_height ||
361 orig_depth != target_depth) {
362 if (tex->get_texture_type() == Texture::TT_3d_texture) {
363 dxgsg9_cat.info()
364 << "Reducing size of " << tex->get_name()
365 << " from " << orig_width << "x" << orig_height << "x" << orig_depth
366 << " to " << target_width << "x" << target_height
367 << "x" << target_depth << "\n";
368 } else {
369 dxgsg9_cat.info()
370 << "Reducing size of " << tex->get_name()
371 << " from " << orig_width << "x" << orig_height
372 << " to " << target_width << "x" << target_height << "\n";
373 }
374
375 shrink_original = true;
376 }
377
378 if (target_width == 0 || target_height == 0) {
379 // We can't create a zero-sized texture, so change it to 1x1.
380 target_width = 1;
381 target_height = 1;
382 }
383
384 const char *error_message;
385
386 error_message = "create_texture failed: couldn't find compatible device Texture Pixel Format for input texture";
387
388 if (dxgsg9_cat.is_spam()) {
389 dxgsg9_cat.spam()
390 << "create_texture handling target bitdepth: " << target_bpp
391 << " alphabits: " << num_alpha_bits << endl;
392 }
393
394 // I could possibly replace some of this logic with
395 // D3DXCheckTextureRequirements(), but it wouldn't handle all my specialized
396 // low-memory cases perfectly
397
398#define CHECK_FOR_FMT(FMT) \
399 if (scrn._supported_tex_formats_mask & FMT##_FLAG) { \
400 target_pixel_format = D3DFMT_##FMT; \
401 goto found_matching_format; }
402
403 if (texture_stored_compressed && compress_texture) {
404 // if the texture is already compressed, we need to choose the
405 // corresponding format, otherwise we might end up cross-compressing from
406 // e.g. DXT5 to DXT3
407 switch (compression_mode){
408 case Texture::CM_dxt1:
409 CHECK_FOR_FMT(DXT1);
410 break;
411 case Texture::CM_dxt2:
412 CHECK_FOR_FMT(DXT2);
413 break;
414 case Texture::CM_dxt3:
415 CHECK_FOR_FMT(DXT3);
416 break;
417 case Texture::CM_dxt4:
418 CHECK_FOR_FMT(DXT4);
419 break;
420 case Texture::CM_dxt5:
421 CHECK_FOR_FMT(DXT5);
422 break;
423 case Texture::CM_rgtc:
424 if (num_color_channels == 1) {
425 CHECK_FOR_FMT(ATI1);
426 } else {
427 CHECK_FOR_FMT(ATI2);
428 }
429 break;
430 }
431
432 // We don't support the compressed format. Fall through.
433 }
434
435 if (compress_texture) {
436 // The ATI1 and ATI2 formats can't be compressed by the driver.
437 // Only choose them if we can compress them on the CPU.
438 // Also, don't choose ATI for a luminance texture, since it gets read as
439 // a texture with just a red channel.
440 if (num_alpha_bits == 0 && !needs_luminance) {
441 if (num_color_channels == 1) {
442 if (scrn._supported_tex_formats_mask & ATI1_FLAG) {
443 if (tex->compress_ram_image(Texture::CM_rgtc)) {
444 target_pixel_format = D3DFMT_ATI1;
445 goto found_matching_format;
446 }
447 }
448 } else if (num_color_channels == 2) {
449 if (scrn._supported_tex_formats_mask & ATI2_FLAG) {
450 if (tex->compress_ram_image(Texture::CM_rgtc)) {
451 target_pixel_format = D3DFMT_ATI2;
452 goto found_matching_format;
453 }
454 }
455 }
456 }
457 if (num_alpha_bits <= 1) {
458 CHECK_FOR_FMT(DXT1);
459 } else if (num_alpha_bits <= 4) {
460 CHECK_FOR_FMT(DXT3);
461 } else {
462 CHECK_FOR_FMT(DXT5);
463 }
464 }
465
466 // We can't compress for some reason, so ensure the uncompressed image is
467 // ready to load.
468 if (texture_stored_compressed) {
470 compression_mode = tex->get_ram_image_compression();
471 texture_stored_compressed = compression_mode != Texture::CM_off;
472 compress_texture = false;
473 }
474
475 // handle each target bitdepth separately. might be less confusing to reorg
476 // by num_color_channels (input type, rather than desired 1st target)
477 switch (target_bpp) {
478
479 // IMPORTANT NOTE: target_bpp is REQUESTED bpp, not what exists in the
480 // texture array (the texture array contains num_color_channels*8bits)
481
482 case 128:
483 // check if format is supported
484 if (scrn._supports_rgba32_texture_format) {
485 target_pixel_format = D3DFMT_A32B32G32R32F;
486 }
487 else {
488 target_pixel_format = scrn._render_to_texture_d3d_format;
489 }
490 goto found_matching_format;
491
492 case 64:
493 // check if format is supported
494 if (scrn._supports_rgba16f_texture_format) {
495 target_pixel_format = D3DFMT_A16B16G16R16F;
496 }
497 else {
498 target_pixel_format = scrn._render_to_texture_d3d_format;
499 }
500 goto found_matching_format;
501
502 case 32:
503 if (needs_depth) {
504 nassertr(num_alpha_bits == 0, false);
505 nassertr(num_color_channels == 1, false);
506
507 CHECK_FOR_FMT(D32);
508 break;
509 }
510
511 if (num_color_channels == 1) {
512 CHECK_FOR_FMT(R32F);
513 CHECK_FOR_FMT(X8R8G8B8);
514 CHECK_FOR_FMT(R8G8B8);
515 break;
516 }
517
518 if (!((num_color_channels == 3) || (num_color_channels == 4)))
519 break; //bail
520
521 CHECK_FOR_FMT(A8R8G8B8);
522
523 if (num_alpha_bits>0) {
524 nassertr(num_color_channels == 4, false);
525
526 // no 32-bit fmt, look for 16 bit walpha (1-15)
527
528 // 32 bit RGBA was requested, but only 16 bit alpha fmts are avail. By
529 // default, convert to 4-4-4-4 which has 4-bit alpha for blurry edges.
530 // If we know tex only needs 1 bit alpha (i.e. for a mask), use 1555
531 // instead.
532
533
534 // ConversionType ConvTo1 = Conv32to16_4444, ConvTo2 = Conv32to16_1555;
535 // DWORD dwAlphaMask1 = 0xF000, dwAlphaMask2 = 0x8000;
536
537 // assume ALPHAMASK is x8000 and RGBMASK is x7fff to simplify 32->16
538 // conversion. This should be true on most cards.
539
540 if (num_alpha_bits == 1) {
541 CHECK_FOR_FMT(A1R5G5B5);
542 }
543
544 // normally prefer 4444 due to better alpha channel resolution
545 CHECK_FOR_FMT(A4R4G4B4);
546 CHECK_FOR_FMT(A1R5G5B5);
547
548 // At this point, bail. Don't worry about converting to non-alpha
549 // formats yet, I think this will be a very rare case.
550 error_message = "create_texture failed: couldn't find compatible Tex DDPIXELFORMAT! no available 16 or 32-bit alpha formats!";
551 } else {
552 // convert 3 or 4 channel to closest 16bpp color fmt
553
554 if (num_color_channels == 3) {
555 CHECK_FOR_FMT(R5G6B5);
556 CHECK_FOR_FMT(X1R5G5B5);
557 } else {
558 CHECK_FOR_FMT(R5G6B5);
559 CHECK_FOR_FMT(X1R5G5B5);
560 }
561 }
562 break;
563
564 case 24:
565 if (needs_depth) {
566 nassertr(num_alpha_bits == 0, false);
567 nassertr(num_color_channels == 1, false);
568
569 // In DirectX 9, all built-in depth formats use shadow map filtering.
570 // Some drivers (GeForce 8000+, Radeon HD 4000+, Intel G45+) expose a
571 // FourCC format called "INTZ" that allows access to the actual depth.
572 if (tex->get_minfilter() == Texture::FT_shadow) {
573 if (needs_stencil) {
574 CHECK_FOR_FMT(D24S8);
575 }
576 CHECK_FOR_FMT(D24X8);
577 CHECK_FOR_FMT(D32);
578 CHECK_FOR_FMT(D16);
579 } else {
580 if (scrn._supported_tex_formats_mask & INTZ_FLAG) {
581 target_pixel_format = D3DFMT_INTZ;
582 goto found_matching_format;
583 }
584
585 // We fall back to a depth format. Chances are that it is going to be
586 // used for shadow mapping, in which case the depth comparison will
587 // probably still result in a useful value.
588 CHECK_FOR_FMT(D24X8);
589 }
590 } else {
591 nassertr(num_color_channels == 3, false);
592
593 CHECK_FOR_FMT(R8G8B8);
594
595 // no 24-bit fmt. look for 32 bit fmt (note: this is memory-hogging
596 // choice instead I could look for memory-conserving 16-bit fmt).
597
598 CHECK_FOR_FMT(X8R8G8B8);
599 CHECK_FOR_FMT(A8R8G8B8);
600
601 // no 24-bit or 32 fmt. look for 16 bit fmt (higher res 565 1st)
602 CHECK_FOR_FMT(R5G6B5);
603 CHECK_FOR_FMT(X1R5G5B5);
604 CHECK_FOR_FMT(A1R5G5B5);
605 }
606 break;
607
608 case 16:
609 if (needs_depth) {
610 nassertr(num_alpha_bits == 0, false);
611 nassertr(num_color_channels == 1, false);
612
613 // In DirectX 9, all built-in depth formats use shadow map filtering.
614 // Some drivers (GeForce 8000+, Radeon HD 4000+, Intel G45+) expose a
615 // FourCC format called "INTZ" that allows access to the actual depth.
616 if (tex->get_minfilter() == Texture::FT_shadow) {
617 if (needs_stencil) {
618 CHECK_FOR_FMT(D24S8);
619 }
620 CHECK_FOR_FMT(D16);
621 CHECK_FOR_FMT(D24X8);
622 CHECK_FOR_FMT(D32);
623 } else {
624 if (scrn._supported_tex_formats_mask & INTZ_FLAG) {
625 target_pixel_format = D3DFMT_INTZ;
626 goto found_matching_format;
627 }
628
629 // We fall back to a depth format. Chances are that it is going to be
630 // used for shadow mapping, in which case the depth comparison will
631 // probably still result in a useful value.
632 CHECK_FOR_FMT(D24X8);
633 }
634
635 } else if (needs_luminance) {
636 nassertr(num_alpha_bits > 0, false);
637 nassertr(num_color_channels == 2, false);
638
639 CHECK_FOR_FMT(A8L8);
640 CHECK_FOR_FMT(A8R8G8B8);
641
642 if (num_alpha_bits == 1) {
643 CHECK_FOR_FMT(A1R5G5B5);
644 }
645
646 // normally prefer 4444 due to better alpha channel resolution
647 CHECK_FOR_FMT(A4R4G4B4);
648 CHECK_FOR_FMT(A1R5G5B5);
649 } else {
650 nassertr((num_color_channels == 3)||(num_color_channels == 4), false);
651 // look for compatible 16bit fmts, if none then give up (don't worry
652 // about other bitdepths for 16 bit)
653 switch(num_alpha_bits) {
654 case 0:
655 if (num_color_channels == 3) {
656 CHECK_FOR_FMT(R5G6B5);
657 CHECK_FOR_FMT(X1R5G5B5);
658 } else {
659 nassertr(num_color_channels == 4, false);
660 // it could be 4 if user asks us to throw away the alpha channel
661 CHECK_FOR_FMT(R5G6B5);
662 CHECK_FOR_FMT(X1R5G5B5);
663 }
664 break;
665 case 1:
666 // app specifically requests 1-5-5-5 F_rgba5 case, where you
667 // explicitly want 1-5-5-5 fmt, as opposed to F_rgbm, which could use
668 // 32bpp ARGB. fail if this particular fmt not avail.
669 nassertr(num_color_channels == 4, false);
670 CHECK_FOR_FMT(X1R5G5B5);
671 break;
672 case 4:
673 // app specifically requests 4-4-4-4 F_rgba4 case, as opposed to
674 // F_rgba, which could use 32bpp ARGB
675 nassertr(num_color_channels == 4, false);
676 CHECK_FOR_FMT(A4R4G4B4);
677 break;
678 default:
679 nassertr(false, false); // problem in get_bits_per_pixel()?
680 }
681 }
682 case 8:
683 if (num_alpha_bits == 8) {
684 // look for 16bpp A8L8, else 32-bit ARGB, else 16-4444.
685
686 // skip 8bit alpha only (D3DFMT_A8), because I think only voodoo
687 // supports it and the voodoo support isn't the kind of blending model
688 // we need somehow (is it that voodoo assumes color is white? isnt that
689 // what we do in ConvAlpha8to32 anyway?)
690
691 CHECK_FOR_FMT(A8L8);
692 CHECK_FOR_FMT(A8R8G8B8);
693 CHECK_FOR_FMT(A4R4G4B4);
694 } else {
695 if (needs_luminance) {
696 // don't bother handling those other 8bit lum fmts like 4-4, since 16
697 // 8-8 is usually supported too
698 nassertr(num_color_channels == 1, false);
699
700 // look for native lum fmt first
701 CHECK_FOR_FMT(L8);
702 }
703
704 CHECK_FOR_FMT(R8G8B8);
705 CHECK_FOR_FMT(X8R8G8B8);
706
707 CHECK_FOR_FMT(R5G6B5);
708 CHECK_FOR_FMT(X1R5G5B5);
709 }
710 break;
711
712 default:
713 error_message = "create_texture failed: unhandled pixel bitdepth in DX loader";
714 }
715
716 // if we've gotten here, haven't found a match
717 dxgsg9_cat.error()
718 << error_message << ": " << tex->get_name() << endl
719 << "NumColorChannels: " << num_color_channels << "; NumAlphaBits: "
720 << num_alpha_bits << "; targetbpp: " <<target_bpp
721 << "; _supported_tex_formats_mask: 0x"
722 << std::hex << scrn._supported_tex_formats_mask << std::dec
723 << "; NeedLuminance: " << needs_luminance << endl;
724 goto error_exit;
725
726
727 found_matching_format:
728 // We found a suitable format that matches the texture's format.
729
730 if (tex->get_match_framebuffer_format()) {
731 // Instead of creating a texture with the found format, we will need to
732 // make one that exactly matches the framebuffer's format. Look up what
733 // that format is.
734 IDirect3DSurface9 *render_target;
735
736 if (needs_depth) {
737 hr = scrn._d3d_device->GetDepthStencilSurface(&render_target);
738 } else {
739 hr = scrn._d3d_device->GetRenderTarget(0, &render_target);
740 }
741 if (FAILED(hr)) {
742 dxgsg9_cat.error()
743 << "GetRenderTgt failed in create_texture: " << D3DERRORSTRING(hr);
744 } else {
745 D3DSURFACE_DESC surface_desc;
746 hr = render_target->GetDesc(&surface_desc);
747 if (FAILED(hr)) {
748 dxgsg9_cat.error()
749 << "GetDesc failed in create_texture: " << D3DERRORSTRING(hr);
750 } else {
751 if (target_pixel_format != surface_desc.Format &&
752 target_pixel_format != D3DFMT_INTZ) {
753 if (dxgsg9_cat.is_debug()) {
754 dxgsg9_cat.debug()
755 << "Chose format " << D3DFormatStr(surface_desc.Format)
756 << " instead of " << D3DFormatStr(target_pixel_format)
757 << " for texture to match framebuffer.\n";
758 }
759 target_pixel_format = surface_desc.Format;
760 }
761 }
762 SAFE_RELEASE(render_target);
763 }
764 }
765
766 // validate magfilter setting degrade filtering if no HW support
767
768 SamplerState::FilterType ft;
769
770 ft = tex->get_magfilter();
771 if ((ft != SamplerState::FT_linear) && ft != SamplerState::FT_nearest) {
772 // mipmap settings make no sense for magfilter
773 if (ft == SamplerState::FT_nearest_mipmap_nearest) {
774 ft = SamplerState::FT_nearest;
775 } else {
776 ft = SamplerState::FT_linear;
777 }
778 }
779
780 if (ft == SamplerState::FT_linear &&
781 (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) {
782 ft = SamplerState::FT_nearest;
783 }
784 tex->set_magfilter(ft);
785
786 // figure out if we are mipmapping this texture
787 ft = tex->get_minfilter();
788 _has_mipmaps = false;
789
790 if (!dx_ignore_mipmaps) { // set if no HW mipmap capable
791 switch(ft) {
792 case SamplerState::FT_nearest_mipmap_nearest:
793 case SamplerState::FT_linear_mipmap_nearest:
794 case SamplerState::FT_nearest_mipmap_linear: // pick nearest in each, interpolate linearly b/w them
795 case SamplerState::FT_linear_mipmap_linear:
796 _has_mipmaps = true;
797 }
798
799 if (dx_mipmap_everything) { // debug toggle, ok to leave in since its just a creation cost
800 _has_mipmaps = true;
801 if (dxgsg9_cat.is_spam()) {
802 if (ft != SamplerState::FT_linear_mipmap_linear) {
803 dxgsg9_cat.spam()
804 << "Forcing trilinear mipmapping on DX texture ["
805 << tex->get_name() << "]\n";
806 }
807 }
808 ft = SamplerState::FT_linear_mipmap_linear;
809 tex->set_minfilter(ft);
810 }
811
812 } else if ((ft == SamplerState::FT_nearest_mipmap_nearest) || // cvt to no-mipmap filter types
813 (ft == SamplerState::FT_nearest_mipmap_linear)) {
814 ft = SamplerState::FT_nearest;
815
816 } else if ((ft == SamplerState::FT_linear_mipmap_nearest) ||
817 (ft == SamplerState::FT_linear_mipmap_linear)) {
818 ft = SamplerState::FT_linear;
819 }
820
821 nassertr((filter_caps & D3DPTFILTERCAPS_MINFPOINT) != 0, false);
822
823#define TRILINEAR_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MINFLINEAR)
824
825 // do any other filter type degradations necessary
826 switch(ft) {
827 case SamplerState::FT_linear_mipmap_linear:
828 if ((filter_caps & TRILINEAR_MIPMAP_TEXFILTERCAPS) != TRILINEAR_MIPMAP_TEXFILTERCAPS) {
829 if (filter_caps & D3DPTFILTERCAPS_MINFLINEAR) {
830 ft = SamplerState::FT_linear_mipmap_nearest;
831 } else {
832 // if you cant do linear in a level, you probably cant do linear bw
833 // levels, so just do nearest-all
834 ft = SamplerState::FT_nearest_mipmap_nearest;
835 }
836 }
837 break;
838
839 case SamplerState::FT_nearest_mipmap_linear:
840 // if we don't have bilinear, do nearest_nearest
841 if (!((filter_caps & D3DPTFILTERCAPS_MIPFPOINT) &&
842 (filter_caps & D3DPTFILTERCAPS_MINFLINEAR))) {
843 ft = SamplerState::FT_nearest_mipmap_nearest;
844 }
845 break;
846
847 case SamplerState::FT_linear_mipmap_nearest:
848 // if we don't have mip linear, do nearest_nearest
849 if (!(filter_caps & D3DPTFILTERCAPS_MIPFLINEAR)) {
850 ft = SamplerState::FT_nearest_mipmap_nearest;
851 }
852 break;
853
854 case SamplerState::FT_linear:
855 if (!(filter_caps & D3DPTFILTERCAPS_MINFLINEAR)) {
856 ft = SamplerState::FT_nearest;
857 }
858 break;
859 }
860
861 tex->set_minfilter(ft);
862
863 uint aniso_degree;
864
865 aniso_degree = 1;
866 if (scrn._d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) {
867 aniso_degree = tex->get_anisotropic_degree();
868 if ((aniso_degree>scrn._d3dcaps.MaxAnisotropy) ||
869 dx_force_anisotropic_filtering) {
870 aniso_degree = scrn._d3dcaps.MaxAnisotropy;
871 }
872 }
873 tex->set_anisotropic_degree(aniso_degree);
874
875#ifdef _DEBUG
876 dxgsg9_cat.spam()
877 << "create_texture: setting aniso degree for " << tex->get_name()
878 << " to: " << aniso_degree << endl;
879#endif
880
881 UINT mip_level_count;
882
883 if (_has_mipmaps) {
884 tex->get_ram_image();
885 mip_level_count = tex->get_num_loadable_ram_mipmap_images();
886 if (mip_level_count < 2) {
887 // tell CreateTex to alloc space for all mip levels down to 1x1
888 mip_level_count = 0;
889
890 if (dxgsg9_cat.is_debug()) {
891 dxgsg9_cat.debug()
892 << "create_texture: generating mipmaps for " << tex->get_name()
893 << endl;
894 }
895 }
896
897 // DirectX will corrupt memory if we try to load mipmaps smaller than 4x4
898 // for ATI1 or ATI2 textures.
899 if (target_pixel_format == D3DFMT_ATI1 ||
900 target_pixel_format == D3DFMT_ATI2) {
901
902 UINT dimension = min(target_height, target_width);
903 mip_level_count = 0;
904 while (dimension >= 4) {
905 ++mip_level_count;
906 dimension >>= 1;
907 }
908
909 if ((UINT)tex->get_num_ram_mipmap_images() < mip_level_count) {
910 // We also have to generate mipmaps on the CPU for these.
912 mip_level_count = min(mip_level_count, (UINT)tex->get_num_ram_mipmap_images());
913 }
914 }
915 } else {
916 mip_level_count = 1;
917 }
918
919 DWORD usage;
920 D3DPOOL pool;
921
922 if (tex->get_render_to_texture ( )) {
923 // REQUIRED PARAMETERS
924 _managed = false;
925 _is_render_target = true;
926
927 pool = D3DPOOL_DEFAULT;
928 if (needs_depth) {
929 usage = D3DUSAGE_DEPTHSTENCIL;
930 } else {
931 usage = D3DUSAGE_RENDERTARGET;
932 }
933 // if (target_bpp <= 32) { target_pixel_format =
934 // scrn._render_to_texture_d3d_format; }
935
936 dxgsg9_cat.debug ()
937 << "*** RENDER TO TEXTURE ***: format "
938 << D3DFormatStr(target_pixel_format)
939 << " "
940 << target_pixel_format
941 << "\n";
942 }
943 else {
944 _managed = scrn._managed_textures;
945 if (_managed) {
946 pool = D3DPOOL_MANAGED;
947 usage = 0;
948 }
949 else {
950 if (scrn._supports_automatic_mipmap_generation) {
951 pool = D3DPOOL_DEFAULT;
952 usage = D3DUSAGE_AUTOGENMIPMAP;
953 }
954 else {
955 if (dx_use_dynamic_textures) {
956 if (scrn._supports_dynamic_textures) {
957 pool = D3DPOOL_DEFAULT;
958 usage = D3DUSAGE_DYNAMIC;
959 }
960 else {
961 // can't lock textures so go back to managed for now need to use
962 // UpdateTexture or UpdateSurface
963 _managed = true;
964 pool = D3DPOOL_MANAGED;
965 usage = 0;
966 }
967 }
968 else {
969 pool = D3DPOOL_DEFAULT;
970 usage = 0;
971 }
972 }
973 }
974 }
975
976 PN_stdfloat bytes_per_texel;
977
978 bytes_per_texel = this -> d3d_format_to_bytes_per_pixel (target_pixel_format);
979 if (bytes_per_texel == 0.0f) {
980 dxgsg9_cat.error()
981 << "D3D create_texture ( ) unknown texture format\n";
982 }
983
984 int data_size;
985
986 data_size = target_width * target_height * target_depth;
987 if (_has_mipmaps) {
988 data_size = (int) ((PN_stdfloat) data_size * 1.3333333);
989 }
990 data_size = (int) ((PN_stdfloat) data_size * bytes_per_texel);
991 if (tex->get_texture_type() == Texture::TT_cube_map) {
992 data_size *= 6;
993 }
994 update_data_size_bytes(data_size);
995
996 int attempts;
997
998 if (dxgsg9_cat.is_debug()) {
999 dxgsg9_cat.debug()
1000 << "Creating " << *tex << ", " << data_size << " bytes, "
1001 << scrn._d3d_device->GetAvailableTextureMem()
1002 << " reported available.\n";
1003 dxgsg9_cat.debug()
1004 << " size is " << target_width << " w * " << target_height << " h * "
1005 << target_depth << " d";
1006 if (_has_mipmaps) {
1007 dxgsg9_cat.debug(false)
1008 << " * 1.3333333 mipmaps";
1009 }
1010 dxgsg9_cat.debug(false)
1011 << " * " << bytes_per_texel << " bpt";
1012 if (tex->get_texture_type() == Texture::TT_cube_map) {
1013 dxgsg9_cat.debug(false)
1014 << " * 6 faces";
1015 }
1016 dxgsg9_cat.debug(false)
1017 << "\n";
1018 }
1019
1020 attempts = 0;
1021 do
1022 {
1023 switch (tex->get_texture_type()) {
1024 case Texture::TT_1d_texture:
1025 case Texture::TT_2d_texture:
1026 hr = scrn._d3d_device->CreateTexture
1027 (target_width, target_height, mip_level_count, usage,
1028 target_pixel_format, pool, &_d3d_2d_texture, nullptr);
1029 _d3d_texture = _d3d_2d_texture;
1030 break;
1031
1032 case Texture::TT_3d_texture:
1033 hr = scrn._d3d_device->CreateVolumeTexture
1034 (target_width, target_height, target_depth, mip_level_count, usage,
1035 target_pixel_format, pool, &_d3d_volume_texture, nullptr);
1036 _d3d_texture = _d3d_volume_texture;
1037 break;
1038
1039 case Texture::TT_cube_map:
1040 hr = scrn._d3d_device->CreateCubeTexture
1041 (target_width, mip_level_count, usage,
1042 target_pixel_format, pool, &_d3d_cube_texture, nullptr);
1043 _d3d_texture = _d3d_cube_texture;
1044
1045 target_height = target_width;
1046 break;
1047 }
1048
1049 attempts++;
1050 } while (scrn._dxgsg9 -> check_dx_allocation (hr, data_size, attempts));
1051
1052 if (FAILED(hr)) {
1053 dxgsg9_cat.error()
1054 << "D3D create_texture failed!" << D3DERRORSTRING(hr);
1055 dxgsg9_cat.error()
1056 << " width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n";
1057
1058 goto error_exit;
1059 }
1060
1061 if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) {
1062 dxgsg9_cat.debug()
1063 << "create_texture: " << tex->get_name()
1064 << " converting panda equivalent of " << D3DFormatStr(_d3d_format)
1065 << " => " << D3DFormatStr(target_pixel_format) << endl;
1066 }
1067
1068 hr = fill_d3d_texture_pixels(scrn, compress_texture);
1069 if (FAILED(hr)) {
1070
1071 dxgsg9_cat.debug ()
1072 << "*** fill_d3d_texture_pixels failed ***: format "
1073 << target_pixel_format
1074 << "\n";
1075
1076 goto error_exit;
1077 }
1078
1079 if (tex->get_post_load_store_cache()) {
1080 tex->set_post_load_store_cache(false);
1081 // OK, get the RAM image, and save it in a BamCache record.
1082 if (extract_texture_data(scrn)) {
1083 if (tex->has_ram_image()) {
1085 PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo");
1086 if (record != nullptr) {
1087 record->set_data(tex, tex);
1088 cache->store(record);
1089 }
1090 }
1091 }
1092 }
1093
1094 // must not put render to texture into LRU
1095 if (!_managed && !tex->get_render_to_texture()) {
1096 scrn._dxgsg9->get_engine()->texture_uploaded(tex);
1097 }
1098 mark_loaded();
1099
1100 return true;
1101
1102 error_exit:
1103
1104 RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
1105 _d3d_2d_texture = nullptr;
1106 _d3d_volume_texture = nullptr;
1107 _d3d_cube_texture = nullptr;
1108 return false;
1109}
1110
1111/**
1112 *
1113 */
1114bool DXTextureContext9::
1115create_simple_texture(DXScreenData &scrn) {
1116 nassertr(IS_VALID_PTR(get_texture()), false);
1117
1118 HRESULT hr;
1119
1121
1122 _d3d_format = D3DFMT_A8R8G8B8;
1123 D3DFORMAT target_pixel_format = D3DFMT_A8R8G8B8;
1124 DWORD target_bpp = 32;
1125 DWORD num_color_channels = 4;
1126
1127 DWORD target_width = (DWORD)get_texture()->get_simple_x_size();
1128 DWORD target_height = (DWORD)get_texture()->get_simple_y_size();
1129 DWORD mip_level_count = 1;
1130 DWORD usage = 0;
1131 D3DPOOL pool = D3DPOOL_MANAGED;
1132
1133 int data_size = target_width * target_height * 4;
1134
1135 hr = scrn._d3d_device->CreateTexture
1136 (target_width, target_height, mip_level_count, usage,
1137 target_pixel_format, pool, &_d3d_2d_texture, nullptr);
1138 _d3d_texture = _d3d_2d_texture;
1139 if (FAILED(hr)) {
1140 dxgsg9_cat.error()
1141 << "D3D create_simple_texture failed!" << D3DERRORSTRING(hr);
1142 dxgsg9_cat.error()
1143 << " width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n";
1144
1145 goto error_exit;
1146 }
1147
1148 if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) {
1149 dxgsg9_cat.debug()
1150 << "create_simple_texture: " << get_texture()->get_name()
1151 << "\n";
1152 }
1153
1154 {
1156
1157 hr = -1;
1158 // hr = fill_d3d_texture_pixels(scrn);
1159
1160 IDirect3DSurface9 *surface = nullptr;
1161 _d3d_2d_texture->GetSurfaceLevel(0, &surface);
1162
1163 RECT source_size;
1164 source_size.left = source_size.top = 0;
1165 source_size.right = target_width;
1166 source_size.bottom = target_height;
1167
1168 DWORD mip_filter = D3DX_FILTER_LINEAR;
1169
1170 hr = D3DXLoadSurfaceFromMemory
1171 (surface, nullptr, nullptr, (LPCVOID)image.p(),
1172 target_pixel_format, target_width * 4, nullptr,
1173 &source_size, mip_filter, (D3DCOLOR)0x0);
1174
1175 RELEASE(surface, dxgsg9, "create_simple_texture Surface", RELEASE_ONCE);
1176 }
1177
1178 if (FAILED(hr)) {
1179 dxgsg9_cat.debug ()
1180 << "*** fill_d3d_texture_pixels failed ***: format "
1181 << target_pixel_format
1182 << "\n";
1183
1184 goto error_exit;
1185 }
1186
1188 return true;
1189
1190 error_exit:
1191 RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
1192 _d3d_2d_texture = nullptr;
1193 _d3d_volume_texture = nullptr;
1194 _d3d_cube_texture = nullptr;
1195 return false;
1196}
1197
1198/**
1199 * Release the surface used to store the texture
1200 */
1203
1204 if (_d3d_texture == nullptr) {
1205 // don't bother printing the msg below, since we already released it.
1206 return;
1207 }
1208
1209 RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
1210 _d3d_2d_texture = nullptr;
1211 _d3d_volume_texture = nullptr;
1212 _d3d_cube_texture = nullptr;
1213}
1214
1215/**
1216 * This method will be called in the draw thread to download the texture
1217 * memory's image into its ram_image value. It returns true on success, false
1218 * otherwise.
1219 */
1222 bool state;
1223 HRESULT hr;
1224
1225 state = false;
1226 Texture *tex = get_texture();
1227 if (tex->get_texture_type() != Texture::TT_2d_texture) {
1228 dxgsg9_cat.error()
1229 << "Not supported: extract_texture_data for " << tex->get_texture_type()
1230 << "\n";
1231 return state;
1232 }
1233 nassertr(IS_VALID_PTR(_d3d_2d_texture), false);
1234
1235 D3DSURFACE_DESC desc;
1236 hr = _d3d_2d_texture->GetLevelDesc(0, &desc);
1237 if (FAILED(hr)) {
1238 dxgsg9_cat.error()
1239 << "Texture::GetLevelDesc() failed!" << D3DERRORSTRING(hr);
1240 return state;
1241 }
1242
1243 int div = 1;
1244 Texture::Format format = Texture::F_rgba;
1245 Texture::CompressionMode compression = Texture::CM_off;
1246
1247 switch (desc.Format) {
1248 case D3DFMT_R8G8B8:
1249 format = Texture::F_rgb;
1250 break;
1251
1252 case D3DFMT_A8R8G8B8:
1253 case D3DFMT_X8R8G8B8:
1254 break;
1255
1256 case D3DFMT_L8:
1257 format = Texture::F_luminance;
1258 break;
1259
1260 case D3DFMT_A8L8:
1261 format = Texture::F_luminance_alpha;
1262 break;
1263
1264 case D3DFMT_D24S8:
1265 format = Texture::F_depth_stencil;
1266 break;
1267
1268 case D3DFMT_D16:
1269 format = Texture::F_depth_component16;
1270 break;
1271
1272 case D3DFMT_D24X8:
1273 format = Texture::F_depth_component24;
1274 break;
1275
1276 case D3DFMT_D32:
1277 format = Texture::F_depth_component32;
1278 break;
1279
1280 case D3DFMT_DXT1:
1281 compression = Texture::CM_dxt1;
1282 div = 4;
1283 break;
1284 case D3DFMT_DXT2:
1285 compression = Texture::CM_dxt2;
1286 div = 4;
1287 break;
1288 case D3DFMT_DXT3:
1289 compression = Texture::CM_dxt3;
1290 div = 4;
1291 break;
1292 case D3DFMT_DXT4:
1293 compression = Texture::CM_dxt4;
1294 div = 4;
1295 break;
1296 case D3DFMT_DXT5:
1297 compression = Texture::CM_dxt5;
1298 div = 4;
1299 break;
1300 case D3DFMT_ATI1:
1301 case D3DFMT_ATI2:
1302 compression = Texture::CM_rgtc;
1303 div = 4;
1304 break;
1305
1306 default:
1307 dxgsg9_cat.error()
1308 << "Cannot extract texture data: unhandled surface format "
1309 << desc.Format << "\n";
1310 return state;
1311 }
1312
1313 int num_levels = _d3d_2d_texture->GetLevelCount();
1314
1315 tex->set_x_size(desc.Width);
1316 tex->set_y_size(desc.Height);
1317 tex->set_z_size(1);
1318 tex->set_component_type(Texture::T_unsigned_byte);
1319 tex->set_format(format);
1320 tex->clear_ram_image();
1321
1322 if (_is_render_target) {
1323 IDirect3DSurface9* source_surface;
1324 IDirect3DSurface9* destination_surface;
1325
1326 source_surface = 0;
1327 destination_surface = 0;
1328
1329 hr = _d3d_2d_texture -> GetSurfaceLevel (0, &source_surface);
1330 if (hr == D3D_OK) {
1331
1332 D3DPOOL pool;
1333 D3DSURFACE_DESC surface_description;
1334
1335 pool = D3DPOOL_SYSTEMMEM;
1336 source_surface -> GetDesc (&surface_description);
1337
1338 hr = screen._d3d_device->CreateOffscreenPlainSurface (
1339 surface_description.Width,
1340 surface_description.Height,
1341 surface_description.Format,
1342 pool,
1343 &destination_surface,
1344 nullptr);
1345 if (hr == D3D_OK) {
1346 if (source_surface && destination_surface) {
1347 hr = screen._d3d_device -> GetRenderTargetData (source_surface, destination_surface);
1348 if (hr == D3D_OK) {
1349
1350 D3DLOCKED_RECT rect;
1351
1352 hr = destination_surface -> LockRect (&rect, nullptr, D3DLOCK_READONLY);
1353 if (hr == D3D_OK) {
1354
1355 unsigned int y;
1356 int size;
1357 int bytes_per_line;
1358
1359 int surface_bytes_per_line;
1360 unsigned char *surface_pointer;
1361
1362 bytes_per_line = surface_description.Width * this -> d3d_format_to_bytes_per_pixel (surface_description.Format);
1363 size = bytes_per_line * surface_description.Height;
1364
1365 surface_bytes_per_line = rect.Pitch;
1366 surface_pointer = (unsigned char *) rect.pBits;
1367
1368 PTA_uchar image = PTA_uchar::empty_array(size);
1369
1370 int offset;
1371
1372 offset = 0;
1373 for (y = 0; y < surface_description.Height; y++)
1374 {
1375 memcpy (&image [offset], surface_pointer, bytes_per_line);
1376
1377 offset += bytes_per_line;
1378 surface_pointer += surface_bytes_per_line;
1379 }
1380
1381 tex->set_ram_image(image, Texture::CM_off);
1382
1383 state = true;
1384
1385 destination_surface -> UnlockRect();
1386 }
1387 }
1388 }
1389
1390 destination_surface -> Release ( );
1391 }
1392 else {
1393 dxgsg9_cat.error()
1394 << "CreateImageSurface failed in extract_texture_data()"
1395 << D3DERRORSTRING(hr);
1396 }
1397 source_surface -> Release ( );
1398 }
1399 }
1400 else {
1401 for (int n = 0; n < num_levels; ++n) {
1402 D3DLOCKED_RECT rect;
1403 hr = _d3d_2d_texture->LockRect(n, &rect, nullptr, D3DLOCK_READONLY);
1404 if (FAILED(hr)) {
1405 dxgsg9_cat.error()
1406 << "Texture::LockRect() failed! level = " << n << " " << D3DERRORSTRING(hr);
1407 return state;
1408 }
1409
1410 int x_size = tex->get_expected_mipmap_x_size(n);
1411 int y_size = tex->get_expected_mipmap_y_size(n);
1412 PTA_uchar image;
1413
1414 if (compression == Texture::CM_off) {
1415 // Uncompressed, but we have to respect the pitch.
1416 int pitch = x_size * tex->get_num_components() * tex->get_component_width();
1417 pitch = min(pitch, (int)rect.Pitch);
1418 int size = pitch * y_size;
1419 image = PTA_uchar::empty_array(size);
1420 if (pitch == rect.Pitch) {
1421 // Easy copy.
1422 memcpy(image.p(), rect.pBits, size);
1423 } else {
1424 // Harder copy: we have to de-interleave DirectX's extra bytes on
1425 // the end of each row.
1426 unsigned char *dest = image.p();
1427 unsigned char *source = (unsigned char *)rect.pBits;
1428 for (int yi = 0; yi < y_size; ++yi) {
1429 memcpy(dest, source, pitch);
1430 dest += pitch;
1431 source += rect.Pitch;
1432 }
1433 }
1434
1435 } else {
1436 // Compressed; just copy the data verbatim.
1437 int size = rect.Pitch * (y_size / div);
1438 image = PTA_uchar::empty_array(size);
1439 memcpy(image.p(), rect.pBits, size);
1440 }
1441
1442 _d3d_2d_texture->UnlockRect(n);
1443 if (n == 0) {
1444 tex->set_ram_image(image, compression);
1445 } else {
1446 tex->set_ram_mipmap_image(n, image);
1447 }
1448 }
1449
1450 state = true;
1451 }
1452
1453 return state;
1454}
1455
1456/**
1457 * copies source_rect in pD3DSurf to upper left of texture
1458 */
1460d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface,
1461 bool inverted, Texture *result, int view, int z) {
1462
1463 // still need custom conversion since d3dd3dx has no way to convert
1464 // arbitrary fmt to ARGB in-memory user buffer
1465
1466 HRESULT hr;
1467 DWORD num_components = result->get_num_components();
1468
1469 nassertr(result->get_component_width() == sizeof(BYTE), E_FAIL); // cant handle anything else now
1470 nassertr(result->get_component_type() == Texture::T_unsigned_byte, E_FAIL); // cant handle anything else now
1471 nassertr((num_components == 3) || (num_components == 4), E_FAIL); // cant handle anything else now
1472 nassertr(IS_VALID_PTR(d3d_surface), E_FAIL);
1473
1474 BYTE *buf = result->modify_ram_image();
1475 if (z >= 0) {
1476 nassertr(z < result->get_z_size(), E_FAIL);
1477 buf += z * result->get_expected_ram_page_size();
1478 }
1479 if (view > 0) {
1480 buf += (view * result->get_z_size()) * result->get_expected_ram_page_size();
1481 }
1482
1483 if (IsBadWritePtr(d3d_surface, sizeof(DWORD))) {
1484 dxgsg9_cat.error()
1485 << "d3d_surface_to_texture failed: bad pD3DSurf ptr value ("
1486 << ((void*)d3d_surface) << ")\n";
1487 exit(1);
1488 }
1489
1490 DWORD x_window_offset, y_window_offset;
1491 DWORD copy_width, copy_height;
1492
1493 D3DLOCKED_RECT locked_rect;
1494 D3DSURFACE_DESC surface_desc;
1495
1496 hr = d3d_surface->GetDesc(&surface_desc);
1497
1498 x_window_offset = source_rect.left, y_window_offset = source_rect.top;
1499 copy_width = RECT_XSIZE(source_rect);
1500 copy_height = RECT_YSIZE(source_rect);
1501
1502 // make sure there's enough space in the texture, its size must match
1503 // (especially xsize) or scanlines will be too long
1504
1505 if (!((copy_width == result->get_x_size()) && (copy_height <= (DWORD)result->get_y_size()))) {
1506 dxgsg9_cat.error()
1507 << "d3d_surface_to_texture, Texture size (" << result->get_x_size()
1508 << ", " << result->get_y_size()
1509 << ") too small to hold display surface ("
1510 << copy_width << ", " << copy_height << ")\n";
1511 nassertr(false, E_FAIL);
1512 return E_FAIL;
1513 }
1514
1515 hr = d3d_surface->LockRect(&locked_rect, nullptr, (D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE));
1516 if (FAILED(hr)) {
1517 dxgsg9_cat.error()
1518 << "d3d_surface_to_texture LockRect() failed!" << D3DERRORSTRING(hr);
1519 return hr;
1520 }
1521
1522 // ones not listed not handled yet
1523 nassertr((surface_desc.Format == D3DFMT_A8R8G8B8) ||
1524 (surface_desc.Format == D3DFMT_X8R8G8B8) ||
1525 (surface_desc.Format == D3DFMT_R8G8B8) ||
1526 (surface_desc.Format == D3DFMT_R5G6B5) ||
1527 (surface_desc.Format == D3DFMT_X1R5G5B5) ||
1528 (surface_desc.Format == D3DFMT_A1R5G5B5) ||
1529 (surface_desc.Format == D3DFMT_A4R4G4B4), E_FAIL);
1530
1531 // buf contains raw ARGB in Texture byteorder
1532
1533 int byte_pitch = locked_rect.Pitch;
1534 BYTE *surface_bytes = (BYTE *)locked_rect.pBits;
1535
1536 if (inverted) {
1537 surface_bytes += byte_pitch * (y_window_offset + copy_height - 1);
1538 byte_pitch = -byte_pitch;
1539 } else {
1540 surface_bytes += byte_pitch * y_window_offset;
1541 }
1542
1543 // writes out last line in DDSurf first in PixelBuf, so Y line order
1544 // precedes inversely
1545
1546 if (DEBUG_SURFACES && dxgsg9_cat.is_debug()) {
1547 dxgsg9_cat.debug()
1548 << "d3d_surface_to_texture converting "
1549 << D3DFormatStr(surface_desc.Format)
1550 << " DDSurf to " << num_components << "-channel panda Texture\n";
1551 }
1552
1553 DWORD *dest_word = (DWORD *)buf;
1554 BYTE *dest_byte = (BYTE *)buf;
1555
1556 switch(surface_desc.Format) {
1557 case D3DFMT_A8R8G8B8:
1558 case D3DFMT_X8R8G8B8: {
1559 if (num_components == 4) {
1560 DWORD *source_word;
1561 BYTE *dest_line = (BYTE*)dest_word;
1562
1563 for (DWORD y = 0; y < copy_height; y++) {
1564 source_word = ((DWORD*)surface_bytes) + x_window_offset;
1565 memcpy(dest_line, source_word, copy_width * 4);
1566 dest_line += copy_width * 4;
1567 surface_bytes += byte_pitch;
1568 }
1569 } else {
1570 // 24bpp texture case (numComponents == 3)
1571 DWORD *source_word;
1572 for (DWORD y = 0; y < copy_height; y++) {
1573 source_word = ((DWORD*)surface_bytes) + x_window_offset;
1574
1575 for (DWORD x = 0; x < copy_width; x++) {
1576 BYTE r, g, b;
1577 DWORD pixel = *source_word;
1578
1579 r = (BYTE)((pixel>>16) & g_LowByteMask);
1580 g = (BYTE)((pixel>> 8) & g_LowByteMask);
1581 b = (BYTE)((pixel ) & g_LowByteMask);
1582
1583 *dest_byte++ = b;
1584 *dest_byte++ = g;
1585 *dest_byte++ = r;
1586 source_word++;
1587 }
1588 surface_bytes += byte_pitch;
1589 }
1590 }
1591 break;
1592 }
1593
1594 case D3DFMT_R8G8B8: {
1595 BYTE *source_byte;
1596
1597 if (num_components == 4) {
1598 for (DWORD y = 0; y < copy_height; y++) {
1599 source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE);
1600 for (DWORD x = 0; x < copy_width; x++) {
1601 DWORD r, g, b;
1602
1603 b = *source_byte++;
1604 g = *source_byte++;
1605 r = *source_byte++;
1606
1607 *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b;
1608 dest_word++;
1609 }
1610 surface_bytes += byte_pitch;
1611 }
1612 } else {
1613 // 24bpp texture case (numComponents == 3)
1614 for (DWORD y = 0; y < copy_height; y++) {
1615 source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE);
1616 memcpy(dest_byte, source_byte, copy_width * 3);
1617 dest_byte += copy_width * 3;
1618 surface_bytes += byte_pitch;
1619 }
1620 }
1621 break;
1622 }
1623
1624 case D3DFMT_R5G6B5:
1625 case D3DFMT_X1R5G5B5:
1626 case D3DFMT_A1R5G5B5:
1627 case D3DFMT_A4R4G4B4: {
1628 WORD *source_word;
1629 // handle 0555, 1555, 0565, 4444 in same loop
1630
1631 BYTE redshift, greenshift, blueshift;
1632 DWORD redmask, greenmask, bluemask;
1633
1634 if (surface_desc.Format == D3DFMT_R5G6B5) {
1635 redshift = (11-3);
1636 redmask = 0xF800;
1637 greenmask = 0x07E0;
1638 greenshift = (5-2);
1639 bluemask = 0x001F;
1640 blueshift = 3;
1641 } else if (surface_desc.Format == D3DFMT_A4R4G4B4) {
1642 redmask = 0x0F00;
1643 redshift = 4;
1644 greenmask = 0x00F0;
1645 greenshift = 0;
1646 bluemask = 0x000F;
1647 blueshift = 4;
1648 } else { // 1555 or x555
1649 redmask = 0x7C00;
1650 redshift = (10-3);
1651 greenmask = 0x03E0;
1652 greenshift = (5-3);
1653 bluemask = 0x001F;
1654 blueshift = 3;
1655 }
1656
1657 if (num_components == 4) {
1658 // Note: these 16bpp loops ignore input alpha completely (alpha is set
1659 // to fully opaque in texture!)
1660
1661 // if we need to capture alpha, probably need to make separate loops for
1662 // diff 16bpp fmts for best speed
1663
1664 for (DWORD y = 0; y < copy_height; y++) {
1665 source_word = ((WORD*)surface_bytes) + x_window_offset;
1666 for (DWORD x = 0; x < copy_width; x++) {
1667 WORD pixel = *source_word;
1668 BYTE r, g, b;
1669
1670 b = (pixel & bluemask) << blueshift;
1671 g = (pixel & greenmask) >> greenshift;
1672 r = (pixel & redmask) >> redshift;
1673
1674 // alpha is just set to 0xFF
1675
1676 *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b;
1677 source_word++;
1678 dest_word++;
1679 }
1680 surface_bytes += byte_pitch;
1681 }
1682 } else {
1683 // 24bpp texture case (numComponents == 3)
1684 for (DWORD y = 0; y < copy_height; y++) {
1685 source_word = ((WORD*)surface_bytes) + x_window_offset;
1686 for (DWORD x = 0; x < copy_width; x++) {
1687 WORD pixel = *source_word;
1688 BYTE r, g, b;
1689
1690 b = (pixel & bluemask) << blueshift;
1691 g = (pixel & greenmask) >> greenshift;
1692 r = (pixel & redmask) >> redshift;
1693
1694 *dest_byte++ = b;
1695 *dest_byte++ = g;
1696 *dest_byte++ = r;
1697
1698 source_word++;
1699 }
1700 surface_bytes += byte_pitch;
1701 }
1702 }
1703 break;
1704 }
1705
1706 default:
1707 dxgsg9_cat.error()
1708 << "d3d_surface_to_texture: unsupported D3DFORMAT!\n";
1709 }
1710
1711 d3d_surface->UnlockRect();
1712 return S_OK;
1713}
1714
1715/**
1716 * local helper function, which calculates the 'row_byte_length' or 'pitch'
1717 * needed for calling D3DXLoadSurfaceFromMemory. Takes compressed formats
1718 * (DXTn) into account.
1719 */
1720static UINT calculate_row_byte_length (int width, int num_color_channels, D3DFORMAT tex_format)
1721{
1722 UINT source_row_byte_length = 0;
1723
1724 // check for compressed textures and adjust source_row_byte_length and
1725 // source_format accordingly
1726 switch (tex_format) {
1727 case D3DFMT_DXT1:
1728 case D3DFMT_ATI1:
1729 // for dxt1 compressed textures, the row_byte_lenght is "the width
1730 // of one row of cells, in bytes" cells are 4 pixels wide, take up 8
1731 // bytes, and at least 1 cell has to be there.
1732 source_row_byte_length = max(1,width / 4)*8;
1733 break;
1734 case D3DFMT_DXT2:
1735 case D3DFMT_DXT3:
1736 case D3DFMT_DXT4:
1737 case D3DFMT_DXT5:
1738 case D3DFMT_ATI2:
1739 // analogue as above, but cells take up 16 bytes
1740 source_row_byte_length = max(1,width / 4)*16;
1741 break;
1742 default:
1743 // no known compression format.. usual calculation
1744 source_row_byte_length = width*num_color_channels;
1745 break;
1746 }
1747 return source_row_byte_length;
1748}
1749
1750/**
1751 * Called from fill_d3d_texture_pixels, this function fills a single mipmap
1752 * with texture data. Takes care of all necessary conversions and error
1753 * handling.
1754 */
1755HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_format)
1756{
1757 // This whole function was refactored out of fill_d3d_texture_pixels to make
1758 // the code more readable and to avoid code duplication.
1759 IDirect3DSurface9 *mip_surface = nullptr;
1760 bool using_temp_buffer = false;
1761 HRESULT hr = E_FAIL;
1762 CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level);
1763 BYTE *pixels = (BYTE*) image.p();
1764 DWORD width = (DWORD) get_texture()->get_expected_mipmap_x_size(mip_level);
1765 DWORD height = (DWORD) get_texture()->get_expected_mipmap_y_size(mip_level);
1766 int component_width = get_texture()->get_component_width();
1767
1768 size_t page_size = get_texture()->get_expected_ram_mipmap_page_size(mip_level);
1769 size_t view_size;
1770 vector_uchar clear_data;
1771 if (page_size > 0) {
1772 if (image.is_null()) {
1773 // Make an image, filled with the texture's clear color.
1774 image = get_texture()->make_ram_mipmap_image(mip_level);
1775 nassertr(!image.is_null(), E_FAIL);
1776 pixels = (BYTE *)image.p();
1777 }
1778 view_size = image.size();
1779 pixels += view_size * get_view();
1780 pixels += page_size * depth_index;
1781 } else {
1782 // This is a 0x0 texture, which gets loaded as though it were 1x1.
1783 width = 1;
1784 height = 1;
1785 clear_data = get_texture()->get_clear_data();
1786 pixels = clear_data.data();
1787 view_size = clear_data.size();
1788 }
1789
1790 if (get_texture()->get_texture_type() == Texture::TT_cube_map) {
1791 nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
1792 hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)depth_index, mip_level, &mip_surface);
1793 } else {
1794 nassertr(IS_VALID_PTR(_d3d_2d_texture), E_FAIL);
1795 hr = _d3d_2d_texture->GetSurfaceLevel(mip_level, &mip_surface);
1796 }
1797
1798 if (FAILED(hr)) {
1799 dxgsg9_cat.error()
1800 << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
1801 << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
1802 return E_FAIL;
1803 }
1804
1805 RECT source_size;
1806 source_size.left = source_size.top = 0;
1807 source_size.right = width;
1808 source_size.bottom = height;
1809
1810 UINT source_row_byte_length = calculate_row_byte_length(width, get_texture()->get_num_components(), source_format);
1811
1812 DWORD mip_filter;
1813 // need filtering if size changes, (also if bitdepth reduced (need
1814 // dithering)??)
1815 mip_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures
1816
1817 if (Texture::is_srgb(get_texture()->get_format())) {
1818 mip_filter |= D3DX_FILTER_SRGB;
1819 }
1820
1821 // D3DXLoadSurfaceFromMemory will load black luminance and we want full
1822 // white, so convert to explicit luminance-alpha format
1823 if (_d3d_format == D3DFMT_A8) {
1824 // alloc buffer for explicit D3DFMT_A8L8
1825 USHORT *temp_buffer = new USHORT[width * height];
1826 if (!IS_VALID_PTR(temp_buffer)) {
1827 dxgsg9_cat.error()
1828 << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n";
1829 goto exit_FillMipmapSurf;
1830 }
1831 using_temp_buffer = true;
1832
1833 USHORT *out_pixels = temp_buffer;
1834 BYTE *source_pixels = pixels + component_width - 1;
1835 for (UINT y = 0; y < height; y++) {
1836 for (UINT x = 0; x < width; x++, source_pixels += component_width, out_pixels++) {
1837 // add full white, which is our interpretation of alpha-only (similar
1838 // to default adding full opaque alpha 0xFF to RGB-only textures)
1839 *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
1840 }
1841 }
1842
1843 source_format = D3DFMT_A8L8;
1844 source_row_byte_length = width * sizeof(USHORT);
1845 pixels = (BYTE*)temp_buffer;
1846 }
1847 else if (_d3d_format == D3DFMT_A32B32G32R32F && source_format == D3DFMT_A32B32G32R32F) {
1848 size_t total_components = (size_t)width * (size_t)height * 4;
1849 float *temp_buffer = new float[total_components];
1850 if (!IS_VALID_PTR(temp_buffer)) {
1851 dxgsg9_cat.error()
1852 << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n";
1853 goto exit_FillMipmapSurf;
1854 }
1855 using_temp_buffer = true;
1856
1857 // Swap red and blue components.
1858 float *out_pixels = (float *)temp_buffer;
1859 const float *source_pixels = (const float *)pixels;
1860 for (size_t i = 0; i < total_components; i += 4) {
1861 out_pixels[i] = source_pixels[i + 2];
1862 out_pixels[i + 1] = source_pixels[i + 1];
1863 out_pixels[i + 2] = source_pixels[i + 0];
1864 out_pixels[i + 3] = source_pixels[i + 3];
1865 }
1866 pixels = (BYTE*)temp_buffer;
1867 }
1868 else if (component_width != 1 && _d3d_format != D3DFMT_R32F) {
1869 // Convert from 16-bit per channel (or larger) format down to 8-bit per
1870 // channel. This throws away precision in the original image, but dx8
1871 // doesn't support high-precision images anyway.
1872
1873 int num_components = get_texture()->get_num_components();
1874 int num_pixels = width * height * num_components;
1875 BYTE *temp_buffer = new BYTE[num_pixels];
1876 if (!IS_VALID_PTR(temp_buffer)) {
1877 dxgsg9_cat.error() << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n";
1878 goto exit_FillMipmapSurf;
1879 }
1880 using_temp_buffer = true;
1881
1882 BYTE *source_pixels = pixels + component_width - 1;
1883 for (int i = 0; i < num_pixels; i++) {
1884 temp_buffer[i] = *source_pixels;
1885 source_pixels += component_width;
1886 }
1887 pixels = (BYTE*)temp_buffer;
1888 }
1889
1890 // filtering may be done here if texture if targetsize != origsize
1891#ifdef DO_PSTATS
1892 GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_row_byte_length * height);
1893#endif
1894 if (source_format == D3DFMT_ATI1 || source_format == D3DFMT_ATI2) {
1895 // These formats are not supported by D3DXLoadSurfaceFromMemory.
1896 D3DLOCKED_RECT rect;
1897 _d3d_2d_texture->LockRect(mip_level, &rect, 0, D3DLOCK_DISCARD);
1898
1899 unsigned char *dest = (unsigned char *)rect.pBits;
1900 memcpy(dest, pixels, view_size);
1901
1902 _d3d_2d_texture->UnlockRect(mip_level);
1903
1904 } else {
1905 hr = D3DXLoadSurfaceFromMemory
1906 (mip_surface, nullptr, nullptr, (LPCVOID)pixels,
1907 source_format, source_row_byte_length, nullptr,
1908 &source_size, mip_filter, (D3DCOLOR)0x0);
1909 if (FAILED(hr)) {
1910 dxgsg9_cat.error()
1911 << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
1912 << ", mip_level " << mip_level
1913 << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
1914 }
1915 }
1916
1917exit_FillMipmapSurf:
1918 if (using_temp_buffer) {
1919 SAFE_DELETE_ARRAY(pixels);
1920 }
1921
1922 RELEASE(mip_surface, dxgsg9, "FillDDTextureMipmapPixels MipSurface texture ptr", RELEASE_ONCE);
1923 return hr;
1924}
1925
1926/**
1927 *
1928 */
1929HRESULT DXTextureContext9::
1930fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
1931 IDirect3DDevice9 *device = scrn._d3d_device;
1932 Texture *tex = get_texture();
1933 nassertr(IS_VALID_PTR(tex), E_FAIL);
1934 if (tex->get_texture_type() == Texture::TT_3d_texture) {
1935 return fill_d3d_volume_texture_pixels(scrn);
1936 }
1937
1938 HRESULT hr = E_FAIL;
1939
1940 CPTA_uchar image;
1941 Texture::CompressionMode image_compression = Texture::CM_off;
1942 if (compress_texture) {
1943 // If we are to be compressing this texture, accept a pre-compressed ram
1944 // image if it is already so.
1945 image = tex->get_ram_image();
1946 if (!image.is_null()) {
1947 image_compression = tex->get_ram_image_compression();
1948 }
1949 } else {
1950 // If we are not to be compressing this texture, we can only accept an
1951 // uncompressed ram image. Ask the texture to give us one, so that
1952 // there's no danger of accidentally getting a pre-compressed image.
1953 image = tex->get_uncompressed_ram_image();
1954 }
1955
1956 if (image.is_null()) {
1957 // The texture doesn't have an image to load. That's ok; it might be a
1958 // texture we've rendered to by frame buffer operations or something.
1959 if (tex->get_render_to_texture()) {
1960 HRESULT result;
1961
1962 if (_d3d_2d_texture) {
1963 // clear render to texture
1964 IDirect3DSurface9 *surface;
1965
1966 result = _d3d_2d_texture -> GetSurfaceLevel (0, &surface);
1967 if (result == D3D_OK) {
1968 D3DSURFACE_DESC surface_description;
1969
1970 if (surface -> GetDesc (&surface_description) == D3D_OK) {
1971 IDirect3DSurface9 *current_render_target;
1972
1973 if (device -> GetRenderTarget (0, &current_render_target) == D3D_OK) {
1974 IDirect3DSurface9 *depth_stencil_surface;
1975
1976 // turn off depth stencil when clearing texture if it exists
1977 depth_stencil_surface = 0;
1978 if (device -> GetDepthStencilSurface (&depth_stencil_surface) == D3D_OK) {
1979 if (device -> SetDepthStencilSurface (nullptr) == D3D_OK) {
1980
1981 }
1982 }
1983
1984 if (device -> SetRenderTarget (0, surface) == D3D_OK) {
1985 DWORD flags;
1986 D3DCOLOR color;
1987
1988 LColor scaled = tex->get_clear_color().fmin(LColor(1)).fmax(LColor::zero());
1989 scaled *= 255;
1990 color = D3DCOLOR_RGBA((int)scaled[0], (int)scaled[1], (int)scaled[2], (int)scaled[3]);
1991 flags = D3DCLEAR_TARGET;
1992 if (device -> Clear (0, nullptr, flags, color, 0.0f, 0) == D3D_OK) {
1993 }
1994 }
1995
1996 // restore depth stencil
1997 if (depth_stencil_surface) {
1998 device -> SetDepthStencilSurface (depth_stencil_surface);
1999 depth_stencil_surface -> Release();
2000 }
2001
2002 // restore render target
2003 device -> SetRenderTarget (0, current_render_target);
2004 current_render_target -> Release();
2005 }
2006 }
2007
2008 surface -> Release();
2009 }
2010 }
2011
2012 return S_OK;
2013 }
2014 }
2015 //nassertr(IS_VALID_PTR((BYTE*)image.p()), E_FAIL);
2016 nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
2017
2018 PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
2019
2020 DWORD orig_depth = (DWORD) tex->get_z_size();
2021 D3DFORMAT source_format = _d3d_format;
2022
2023 // check for compressed textures and adjust source_format accordingly
2024 switch (image_compression) {
2025 case Texture::CM_dxt1:
2026 source_format = D3DFMT_DXT1;
2027 break;
2028 case Texture::CM_dxt2:
2029 source_format = D3DFMT_DXT2;
2030 break;
2031 case Texture::CM_dxt3:
2032 source_format = D3DFMT_DXT3;
2033 break;
2034 case Texture::CM_dxt4:
2035 source_format = D3DFMT_DXT4;
2036 break;
2037 case Texture::CM_dxt5:
2038 source_format = D3DFMT_DXT5;
2039 break;
2040 case Texture::CM_rgtc:
2041 if (tex->get_num_components() == 1) {
2042 source_format = D3DFMT_ATI1;
2043 } else {
2044 source_format = D3DFMT_ATI2;
2045 }
2046 break;
2047 default:
2048 // no known compression format.. no adjustment
2049 break;
2050 }
2051
2052 for (unsigned int di = 0; di < orig_depth; di++) {
2053
2054 // fill top level mipmap
2055 hr = fill_d3d_texture_mipmap_pixels(0, di, source_format);
2056 if (FAILED(hr)) {
2057 return hr; // error message was already output in fill_d3d_texture_mipmap_pixels
2058 }
2059
2060 if (_has_mipmaps) {
2061 // if we have pre-calculated mipmap levels, use them, otherwise generate
2062 // on the fly
2063 int miplevel_count = _d3d_texture->GetLevelCount();
2064 if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
2065 dxgsg9_cat.debug()
2066 << "Using pre-calculated mipmap levels for texture " << tex->get_name() << "\n";
2067
2068 for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) {
2069 hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format);
2070 if (FAILED(hr)) {
2071 return hr; // error message was already output in fill_d3d_texture_mipmap_pixels
2072 }
2073 }
2074 }
2075 else {
2076 // mipmaps need to be generated, either use autogen or d3dx functions
2077
2078 if (_managed == false && scrn._supports_automatic_mipmap_generation) {
2079 if (false)
2080 {
2081 // hr = _d3d_texture -> SetAutoGenFilterType
2082 // (D3DTEXF_PYRAMIDALQUAD); hr = _d3d_texture ->
2083 // SetAutoGenFilterType (D3DTEXF_GAUSSIANQUAD); hr = _d3d_texture
2084 // -> SetAutoGenFilterType (D3DTEXF_ANISOTROPIC);
2085 hr = _d3d_texture -> SetAutoGenFilterType (D3DTEXF_LINEAR);
2086 if (FAILED(hr)) {
2087 dxgsg9_cat.error() << "SetAutoGenFilterType failed " << D3DERRORSTRING(hr);
2088 }
2089
2090 _d3d_texture -> GenerateMipSubLevels ( );
2091 }
2092 }
2093 else {
2094 DWORD mip_filter_flags;
2095 if (!dx_use_triangle_mipgen_filter) {
2096 mip_filter_flags = D3DX_FILTER_BOX;
2097 } else {
2098 mip_filter_flags = D3DX_FILTER_TRIANGLE;
2099 }
2100
2101 if (Texture::is_srgb(tex->get_format())) {
2102 mip_filter_flags |= D3DX_FILTER_SRGB;
2103 }
2104
2105 // mip_filter_flags |= D3DX_FILTER_DITHER;
2106 hr = D3DXFilterTexture(_d3d_texture, nullptr, 0,
2107 mip_filter_flags);
2108
2109 if (FAILED(hr)) {
2110 dxgsg9_cat.error()
2111 << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
2112 << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
2113 }
2114 }
2115 }
2116 }
2117 }
2118
2119 return hr;
2120}
2121
2122
2123/**
2124 *
2125 */
2126HRESULT DXTextureContext9::
2127fill_d3d_volume_texture_pixels(DXScreenData &scrn) {
2128 Texture *tex = get_texture();
2129 HRESULT hr = E_FAIL;
2130 nassertr(IS_VALID_PTR(tex), E_FAIL);
2131
2132 CPTA_uchar image;
2133 if (scrn._dxgsg9->get_supports_compressed_texture()) {
2134 image = tex->get_ram_image();
2135 } else {
2136 image = tex->get_uncompressed_ram_image();
2137 }
2138
2139 Texture::CompressionMode image_compression;
2140 if (image.is_null()) {
2141 image_compression = Texture::CM_off;
2142 } else {
2143 image_compression = tex->get_ram_image_compression();
2144 }
2145
2146 if (!scrn._dxgsg9->get_supports_compressed_texture_format(image_compression)) {
2147 image = tex->get_uncompressed_ram_image();
2148 image_compression = Texture::CM_off;
2149 }
2150
2151 if (image.is_null()) {
2152 // The texture doesn't have an image to load. That's ok; it might be a
2153 // texture we've rendered to by frame buffer operations or something.
2154 return S_OK;
2155 }
2156
2157 PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
2158
2159 nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
2160 nassertr(tex->get_texture_type() == Texture::TT_3d_texture, E_FAIL);
2161
2162 DWORD orig_width = (DWORD) tex->get_x_size();
2163 DWORD orig_height = (DWORD) tex->get_y_size();
2164 DWORD orig_depth = (DWORD) tex->get_z_size();
2165 DWORD num_color_channels = tex->get_num_components();
2166 D3DFORMAT source_format = _d3d_format;
2167 BYTE *image_pixels = (BYTE*)image.p();
2168 int component_width = tex->get_component_width();
2169
2170 nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
2171
2172 size_t view_size = tex->get_ram_mipmap_view_size(0);
2173 image_pixels += view_size * get_view();
2174
2175 IDirect3DVolume9 *mip_level_0 = nullptr;
2176 bool using_temp_buffer = false;
2177 BYTE *pixels = image_pixels;
2178
2179 nassertr(IS_VALID_PTR(_d3d_volume_texture), E_FAIL);
2180 hr = _d3d_volume_texture->GetVolumeLevel(0, &mip_level_0);
2181
2182 if (FAILED(hr)) {
2183 dxgsg9_cat.error()
2184 << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
2185 << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
2186 return E_FAIL;
2187 }
2188
2189 D3DBOX source_size;
2190 source_size.Left = source_size.Top = source_size.Front = 0;
2191 source_size.Right = orig_width;
2192 source_size.Bottom = orig_height;
2193 source_size.Back = orig_depth;
2194
2195 UINT source_row_byte_length = orig_width * num_color_channels;
2196 UINT source_page_byte_length = orig_height * source_row_byte_length;
2197
2198 DWORD level_0_filter, mip_filter_flags;
2199 using_temp_buffer = false;
2200
2201 // need filtering if size changes, (also if bitdepth reduced (need
2202 // dithering)??)
2203 level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures
2204
2205 if (Texture::is_srgb(tex->get_format())) {
2206 level_0_filter |= D3DX_FILTER_SRGB;
2207 }
2208
2209 // D3DXLoadSurfaceFromMemory will load black luminance and we want full
2210 // white, so convert to explicit luminance-alpha format
2211 if (_d3d_format == D3DFMT_A8) {
2212 // alloc buffer for explicit D3DFMT_A8L8
2213 USHORT *temp_buffer = new USHORT[orig_width * orig_height * orig_depth];
2214 if (!IS_VALID_PTR(temp_buffer)) {
2215 dxgsg9_cat.error()
2216 << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
2217 goto exit_FillDDSurf;
2218 }
2219 using_temp_buffer = true;
2220
2221 USHORT *out_pixels = temp_buffer;
2222 BYTE *source_pixels = pixels + component_width - 1;
2223 for (UINT z = 0; z < orig_depth; z++) {
2224 for (UINT y = 0; y < orig_height; y++) {
2225 for (UINT x = 0;
2226 x < orig_width;
2227 x++, source_pixels += component_width, out_pixels++) {
2228 // add full white, which is our interpretation of alpha-only
2229 // (similar to default adding full opaque alpha 0xFF to RGB-only
2230 // textures)
2231 *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
2232 }
2233 }
2234 }
2235
2236 source_format = D3DFMT_A8L8;
2237 source_row_byte_length = orig_width * sizeof(USHORT);
2238 source_page_byte_length = orig_height * source_row_byte_length;
2239 pixels = (BYTE*)temp_buffer;
2240 }
2241 else if (_d3d_format == D3DFMT_A32B32G32R32F && source_format == D3DFMT_A32B32G32R32F) {
2242 size_t total_components = (size_t)orig_width * (size_t)orig_height * (size_t)orig_depth * 4;
2243 float *temp_buffer = new float[total_components];
2244 if (!IS_VALID_PTR(temp_buffer)) {
2245 dxgsg9_cat.error()
2246 << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
2247 goto exit_FillDDSurf;
2248 }
2249 using_temp_buffer = true;
2250
2251 // Swap red and blue components.
2252 float *out_pixels = (float *)temp_buffer;
2253 const float *source_pixels = (const float *)pixels;
2254 for (size_t i = 0; i < total_components; i += 4) {
2255 out_pixels[i] = source_pixels[i + 2];
2256 out_pixels[i + 1] = source_pixels[i + 1];
2257 out_pixels[i + 2] = source_pixels[i + 0];
2258 out_pixels[i + 3] = source_pixels[i + 3];
2259 }
2260 pixels = (BYTE*)temp_buffer;
2261 }
2262 else if (component_width != 1 && _d3d_format != D3DFMT_R32F) {
2263 // Convert from 16-bit per channel (or larger) format down to 8-bit per
2264 // channel. This throws away precision in the original image, but dx8
2265 // doesn't support high-precision images anyway.
2266
2267 int num_components = tex->get_num_components();
2268 int num_pixels = orig_width * orig_height * orig_depth * num_components;
2269 BYTE *temp_buffer = new BYTE[num_pixels];
2270 if (!IS_VALID_PTR(temp_buffer)) {
2271 dxgsg9_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
2272 goto exit_FillDDSurf;
2273 }
2274 using_temp_buffer = true;
2275
2276 BYTE *source_pixels = pixels + component_width - 1;
2277 for (int i = 0; i < num_pixels; i++) {
2278 temp_buffer[i] = *source_pixels;
2279 source_pixels += component_width;
2280 }
2281 pixels = (BYTE*)temp_buffer;
2282 }
2283
2284
2285 // filtering may be done here if texture if targetsize != origsize
2286#ifdef DO_PSTATS
2287 GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_page_byte_length * orig_depth);
2288#endif
2289 hr = D3DXLoadVolumeFromMemory
2290 (mip_level_0, nullptr, nullptr, (LPCVOID)pixels,
2291 source_format, source_row_byte_length, source_page_byte_length,
2292 nullptr,
2293 &source_size, level_0_filter, (D3DCOLOR)0x0);
2294 if (FAILED(hr)) {
2295 dxgsg9_cat.error()
2296 << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
2297 << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr);
2298 goto exit_FillDDSurf;
2299 }
2300
2301 if (_has_mipmaps) {
2302 if (!dx_use_triangle_mipgen_filter) {
2303 mip_filter_flags = D3DX_FILTER_BOX;
2304 } else {
2305 mip_filter_flags = D3DX_FILTER_TRIANGLE;
2306 }
2307
2308 if (Texture::is_srgb(tex->get_format())) {
2309 mip_filter_flags |= D3DX_FILTER_SRGB;
2310 }
2311
2312 // mip_filter_flags| = D3DX_FILTER_DITHER;
2313
2314 hr = D3DXFilterTexture(_d3d_texture, nullptr, 0,
2315 mip_filter_flags);
2316 if (FAILED(hr)) {
2317 dxgsg9_cat.error()
2318 << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
2319 << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
2320 goto exit_FillDDSurf;
2321 }
2322 }
2323
2324 exit_FillDDSurf:
2325 if (using_temp_buffer) {
2326 SAFE_DELETE_ARRAY(pixels);
2327 }
2328 RELEASE(mip_level_0, dxgsg9, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE);
2329 return hr;
2330}
2331
2332
2333/**
2334 * Returns the largest power of 2 less than or equal to value.
2335 */
2336int DXTextureContext9::
2337down_to_power_2(int value) {
2338 int x = 1;
2339 while ((x << 1) <= value) {
2340 x = (x << 1);
2341 }
2342 return x;
2343}
2344
2345/**
2346 * Maps from the Texture's Format symbols to bpp. Returns # of alpha bits.
2347 * Note: Texture's format indicates REQUESTED final format, not the stored
2348 * format, which is indicated by pixelbuffer type
2349 */
2350unsigned int DXTextureContext9::
2351get_bits_per_pixel(Texture::Format format, int *alphbits) {
2352 *alphbits = 0; // assume no alpha bits
2353 switch(format) {
2354 case Texture::F_alpha:
2355 *alphbits = 8;
2356 case Texture::F_color_index:
2357 case Texture::F_red:
2358 case Texture::F_green:
2359 case Texture::F_blue:
2360 case Texture::F_rgb332:
2361 return 8;
2362 case Texture::F_luminance_alphamask:
2363 *alphbits = 1;
2364 return 16;
2365 case Texture::F_luminance_alpha:
2366 *alphbits = 8;
2367 return 16;
2368 case Texture::F_luminance:
2369 return 8;
2370 case Texture::F_rgba4:
2371 *alphbits = 4;
2372 return 16;
2373 case Texture::F_rgba5:
2374 *alphbits = 1;
2375 return 16;
2376 case Texture::F_depth_component:
2377 case Texture::F_depth_component16:
2378 return 16;
2379 case Texture::F_depth_stencil:
2380 case Texture::F_depth_component24:
2381 return 24;
2382 case Texture::F_depth_component32:
2383 return 32;
2384 case Texture::F_rgb5:
2385 return 16;
2386 case Texture::F_rgb8:
2387 case Texture::F_rgb:
2388 return 24;
2389 case Texture::F_rgba8:
2390 case Texture::F_rgba:
2391 *alphbits = 8;
2392 return 32;
2393 case Texture::F_rgbm:
2394 *alphbits = 1;
2395 return 32;
2396 case Texture::F_rgb12:
2397 return 36;
2398 case Texture::F_rgba12:
2399 *alphbits = 12;
2400 return 48;
2401 case Texture::F_rgba16:
2402 *alphbits = 16;
2403 return 64;
2404 case Texture::F_rgba32:
2405 *alphbits = 32;
2406 return 128;
2407
2408 case Texture::F_r32:
2409 return 32;
2410
2411 case Texture::F_srgb:
2412 return 24;
2413 case Texture::F_srgb_alpha:
2414 *alphbits = 8;
2415 return 32;
2416 case Texture::F_sluminance:
2417 return 8;
2418 case Texture::F_sluminance_alpha:
2419 *alphbits = 8;
2420 return 16;
2421 }
2422 return 8;
2423}
2424
2425/**
2426 * Determines bytes per pixel from D3DFORMAT.
2427 */
2428PN_stdfloat DXTextureContext9::
2429d3d_format_to_bytes_per_pixel (D3DFORMAT format)
2430{
2431 PN_stdfloat bytes_per_pixel;
2432
2433 bytes_per_pixel = 0.0f;
2434 switch (format)
2435 {
2436 case D3DFMT_R3G3B2:
2437 case D3DFMT_A8:
2438 case D3DFMT_A8P8:
2439 case D3DFMT_P8:
2440 case D3DFMT_L8:
2441 case D3DFMT_A4L4:
2442 bytes_per_pixel = 1.0f;
2443 break;
2444
2445 case D3DFMT_R16F:
2446 case D3DFMT_CxV8U8:
2447 case D3DFMT_V8U8:
2448 case D3DFMT_R5G6B5:
2449 case D3DFMT_X1R5G5B5:
2450 case D3DFMT_A1R5G5B5:
2451 case D3DFMT_A4R4G4B4:
2452 case D3DFMT_L16:
2453 case D3DFMT_A8L8:
2454 case D3DFMT_A8R3G3B2:
2455 case D3DFMT_X4R4G4B4:
2456 case D3DFMT_D16:
2457 case (D3DFORMAT)MAKEFOURCC('D', 'F', '1', '6'):
2458 bytes_per_pixel = 2.0f;
2459 break;
2460
2461 case D3DFMT_R8G8B8:
2462 bytes_per_pixel = 3.0f;
2463 break;
2464
2465 case D3DFMT_G16R16F:
2466 case D3DFMT_Q8W8V8U8:
2467 case D3DFMT_V16U16:
2468 case D3DFMT_R32F:
2469 case D3DFMT_A8R8G8B8:
2470 case D3DFMT_X8R8G8B8:
2471 case D3DFMT_A2B10G10R10:
2472 case D3DFMT_A8B8G8R8:
2473 case D3DFMT_X8B8G8R8:
2474 case D3DFMT_G16R16:
2475 case D3DFMT_A2R10G10B10:
2476 case D3DFMT_D24X8:
2477 case D3DFMT_D24S8:
2478 case D3DFMT_D32:
2479 case (D3DFORMAT)MAKEFOURCC('D', 'F', '2', '4'):
2480 case D3DFMT_INTZ:
2481 bytes_per_pixel = 4.0f;
2482 break;
2483
2484 case D3DFMT_G32R32F:
2485 case D3DFMT_A16B16G16R16F:
2486 case D3DFMT_Q16W16V16U16:
2487 case D3DFMT_A16B16G16R16:
2488 bytes_per_pixel = 8.0f;
2489 break;
2490
2491 case D3DFMT_A32B32G32R32F:
2492 bytes_per_pixel = 16.0f;
2493 break;
2494
2495 case D3DFMT_DXT1:
2496 case D3DFMT_ATI1:
2497 bytes_per_pixel = 0.5f;
2498 break;
2499 case D3DFMT_DXT2:
2500 case D3DFMT_DXT3:
2501 case D3DFMT_DXT4:
2502 case D3DFMT_DXT5:
2503 case D3DFMT_ATI2:
2504 bytes_per_pixel = 1.0f;
2505 break;
2506 }
2507
2508 return bytes_per_pixel;
2509}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void mark_used_lru() const
To be called when the page is used; this will move it to the tail of the AdaptiveLru queue it is alre...
void dequeue_lru()
Removes the page from its AdaptiveLru.
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
set_data
Stores a new data object on the record.
This class maintains a cache of Bam and/or Txo objects generated from model files and texture images ...
Definition bamCache.h:42
bool store(BamCacheRecord *record)
Flushes a cache entry to disk.
Definition bamCache.cxx:194
static BamCache * get_global_ptr()
Returns a pointer to the global BamCache object, which is used automatically by the ModelPool and Tex...
Definition bamCache.I:223
const Element * p() const
Function p() is similar to the function from ConstPointerTo.
bool create_texture(DXScreenData &scrn)
Use panda texture's pixelbuffer to create a texture for the specified device.
virtual void evict_lru()
Evicts the page from the LRU.
bool extract_texture_data(DXScreenData &scrn)
This method will be called in the draw thread to download the texture memory's image into its ram_ima...
void delete_texture()
Release the surface used to store the texture.
static HRESULT d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface, bool inverted, Texture *result, int view, int z)
copies source_rect in pD3DSurf to upper left of texture
void texture_uploaded(Texture *tex)
This method is called by the GraphicsStateGuardian after a texture has been successfully uploaded to ...
GraphicsEngine * get_engine() const
Returns the graphics engine that created this GSG.
virtual bool get_supports_compressed_texture_format(int compression_mode) const
Returns true if this GSG can accept textures pre-compressed in the indicated format.
get_supports_compressed_texture
Returns true if this GSG can compress textures as it loads them into texture memory,...
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition pStatTimer.h:30
constexpr bool is_null() const
Returns true if the PointerTo is a NULL pointer, false otherwise.
A table of objects that are saved within the graphics context for reference by handle later.
This is a special class object that holds all the information returned by a particular GSG to indicat...
void update_data_size_bytes(size_t new_data_size_bytes)
Should be called (usually by a derived class) when the on-card size of this object has changed.
Texture * get_texture() const
Returns the pointer to the associated Texture object.
void mark_simple_loaded()
Should be called after the texture's "simple" image has been loaded into graphics memory.
void mark_unloaded()
Should be called after the texture has been forced out of texture memory.
void mark_loaded()
Should be called after the texture has been loaded into graphics memory, this updates the internal fl...
int get_view() const
Returns the specific view of a multiview texture this context represents.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition texture.h:72
get_post_load_store_cache
Returns the setting of the post_load_store_cache flag.
Definition texture.h:597
CPTA_uchar get_uncompressed_ram_image()
Returns the system-RAM image associated with the texture, in an uncompressed form if at all possible.
Definition texture.I:1404
get_format
Returns the format of the texture, which represents both the semantic meaning of the texels and,...
Definition texture.h:371
get_minfilter
Returns the filter mode of the texture for minification.
Definition texture.h:392
void generate_ram_mipmap_images()
Automatically fills in the n mipmap levels of the Texture, based on the texture's source image.
Definition texture.I:1692
PTA_uchar modify_ram_image()
Returns a modifiable pointer to the system-RAM image.
Definition texture.I:1383
set_z_size
Changes the z size indicated for the texture.
Definition texture.h:351
get_render_to_texture
Returns a flag on the texture that indicates whether the texture is intended to be used as a direct-r...
Definition texture.h:418
get_compression
Returns the compression mode requested for this particular texture, or CM_off if the texture is not t...
Definition texture.h:414
bool has_ram_image() const
Returns true if the Texture has its image contents available in main RAM, false if it exists only in ...
Definition texture.I:1243
get_texture_type
Returns the overall interpretation of the texture.
Definition texture.h:366
CPTA_uchar get_ram_image()
Returns the system-RAM image data associated with the texture.
Definition texture.I:1357
get_simple_ram_image
Returns the image data associated with the "simple" texture image.
Definition texture.h:520
static bool is_srgb(Format format)
Returns true if the indicated format is in the sRGB color space, false otherwise.
Definition texture.cxx:2678
get_ram_image_compression
Returns the compression mode in which the ram image is already stored pre- compressed.
Definition texture.h:472
set_format
Changes the format value for the texture components.
Definition texture.h:371
get_component_width
Returns the number of bytes stored for each color component of a texel.
Definition texture.h:365
vector_uchar get_clear_data() const
Returns the raw image data for a single pixel if it were set to the clear color.
Definition texture.I:288
set_anisotropic_degree
Specifies the level of anisotropic filtering to apply to the texture.
Definition texture.h:404
get_anisotropic_degree
Returns the degree of anisotropic filtering that should be applied to the texture.
Definition texture.h:404
get_match_framebuffer_format
Returns true if the special flag was set that indicates to the GSG that the Texture's format should b...
Definition texture.h:592
get_y_size
Returns the height of the texture image in texels.
Definition texture.h:347
bool compress_ram_image(CompressionMode compression=CM_on, QualityLevel quality_level=QL_default, GraphicsStateGuardianBase *gsg=nullptr)
Attempts to compress the texture's RAM image internally, to a format supported by the indicated GSG.
Definition texture.I:1480
size_t get_ram_mipmap_view_size(int n) const
Returns the number of bytes used by the in-memory image per view for mipmap level n,...
Definition texture.I:1577
get_magfilter
Returns the filter mode of the texture for magnification.
Definition texture.h:398
get_z_size
Returns the depth of the texture image in texels.
Definition texture.h:351
set_x_size
Changes the x size indicated for the texture.
Definition texture.h:343
void set_ram_mipmap_image(int n, CPTA_uchar image, size_t page_size=0)
Replaces the current system-RAM image for the indicated mipmap level with the new data.
Definition texture.I:1665
size_t get_expected_ram_mipmap_page_size(int n) const
Returns the number of bytes that should be used per each Z page of the 3-d texture,...
Definition texture.I:1625
set_minfilter
Sets the filtering method that should be used when viewing the texture from a distance.
Definition texture.h:392
set_magfilter
Sets the filtering method that should be used when viewing the texture up close.
Definition texture.h:398
PTA_uchar make_ram_mipmap_image(int n)
Discards the current system-RAM image for the nth mipmap level, if any, and allocates a new buffer of...
Definition texture.I:1651
int get_expected_mipmap_x_size(int n) const
Returns the x_size that the nth mipmap level should have, based on the texture's size.
Definition texture.I:1186
get_num_components
Returns the number of color components for each texel of the texture image.
Definition texture.h:364
void clear_ram_image()
Discards the current system-RAM image.
Definition texture.I:1440
get_fullpath
Returns the fullpath that has been set.
Definition texture.h:333
get_x_size
Returns the width of the texture image in texels.
Definition texture.h:343
get_simple_y_size
Returns the height of the "simple" image in texels.
Definition texture.h:519
get_expected_ram_page_size
Returns the number of bytes that should be used per each Z page of the 3-d texture.
Definition texture.h:450
int get_expected_mipmap_y_size(int n) const
Returns the y_size that the nth mipmap level should have, based on the texture's size.
Definition texture.I:1196
set_y_size
Changes the y size indicated for the texture.
Definition texture.h:347
set_post_load_store_cache
Sets the post_load_store_cache flag.
Definition texture.h:597
get_component_type
Returns the numeric interpretation of each component of the texture.
Definition texture.h:375
void set_ram_image(CPTA_uchar image, CompressionMode compression=CM_off, size_t page_size=0)
Replaces the current system-RAM image with the new data.
Definition texture.I:1430
get_simple_x_size
Returns the width of the "simple" image in texels.
Definition texture.h:518
get_num_loadable_ram_mipmap_images
Returns the number of contiguous mipmap levels that exist in RAM, up until the first gap in the seque...
Definition texture.h:505
CPTA_uchar get_ram_mipmap_image(int n) const
Returns the system-RAM image data associated with the nth mipmap level, if present.
Definition texture.cxx:1214
get_clear_color
Returns the color that was previously set using set_clear_color.
Definition texture.h:279
set_component_type
Changes the data value for the texture components.
Definition texture.h:375
get_num_ram_mipmap_images
Returns the maximum number of mipmap level images available in system memory.
Definition texture.h:504
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.