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