Panda3D
dxGraphicsStateGuardian9.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 dxGraphicsStateGuardian9.cxx
10  * @author mike
11  * @date 1999-02-02
12  * @author fperazzi, PandaSE
13  * @date 2010-05-05
14  */
15 
17 #include "config_dxgsg9.h"
18 #include "displayRegion.h"
19 #include "renderBuffer.h"
20 #include "geom.h"
21 #include "graphicsWindow.h"
22 #include "graphicsEngine.h"
23 #include "lens.h"
24 #include "ambientLight.h"
25 #include "directionalLight.h"
26 #include "pointLight.h"
27 #include "spotlight.h"
28 #include "textureAttrib.h"
29 #include "texGenAttrib.h"
30 #include "shadeModelAttrib.h"
31 #include "cullFaceAttrib.h"
32 #include "transparencyAttrib.h"
33 #include "alphaTestAttrib.h"
34 #include "depthTestAttrib.h"
35 #include "depthWriteAttrib.h"
36 #include "colorWriteAttrib.h"
37 #include "texMatrixAttrib.h"
38 #include "materialAttrib.h"
39 #include "renderModeAttrib.h"
40 #include "rescaleNormalAttrib.h"
41 #include "fogAttrib.h"
42 #include "depthOffsetAttrib.h"
43 #include "lightAttrib.h"
44 #include "stencilAttrib.h"
45 #include "scissorAttrib.h"
46 #include "clipPlaneAttrib.h"
47 #include "fog.h"
48 #include "throw_event.h"
49 #include "geomVertexFormat.h"
50 #include "geomVertexData.h"
51 #include "geomTriangles.h"
52 #include "geomTristrips.h"
53 #include "geomTrifans.h"
54 #include "geomLines.h"
55 #include "geomLinestrips.h"
56 #include "geomPoints.h"
57 #include "geomVertexReader.h"
58 #include "dxGeomMunger9.h"
59 #include "config_gobj.h"
60 #include "dxVertexBufferContext9.h"
61 #include "dxIndexBufferContext9.h"
63 #include "pStatTimer.h"
64 #include "pStatCollector.h"
65 #include "wdxGraphicsBuffer9.h"
66 #include "config_pgraph.h"
67 #include "shaderGenerator.h"
68 #ifdef HAVE_CG
69 #include <Cg/cgD3D9.h>
70 #endif
71 
72 #include <mmsystem.h>
73 
74 #include <dxsdkver.h>
75 
76 #define tostring(x) #x
77 #define SDK_VERSION(major,minor) tostring(major) << "." << tostring(minor)
78 #define DIRECTX_SDK_VERSION SDK_VERSION (_DXSDK_PRODUCT_MAJOR, _DXSDK_PRODUCT_MINOR) << "." << SDK_VERSION (_DXSDK_BUILD_MAJOR, _DXSDK_BUILD_MINOR)
79 
80 using std::endl;
81 using std::max;
82 using std::min;
83 
84 TypeHandle DXGraphicsStateGuardian9::_type_handle;
85 
86 D3DMATRIX DXGraphicsStateGuardian9::_d3d_ident_mat;
87 
88 unsigned char *DXGraphicsStateGuardian9::_temp_buffer = nullptr;
89 unsigned char *DXGraphicsStateGuardian9::_safe_buffer_start = nullptr;
90 
91 #ifdef HAVE_CG
92 LPDIRECT3DDEVICE9 DXGraphicsStateGuardian9::_cg_device = nullptr;
93 #endif
94 
95 #define __D3DLIGHT_RANGE_MAX ((PN_stdfloat)sqrt(FLT_MAX)) //for some reason this is missing in dx9 hdrs
96 
97 #define MY_D3DRGBA(r, g, b, a) ((D3DCOLOR) D3DCOLOR_COLORVALUE(r, g, b, a))
98 
99 /**
100  *
101  */
102 DXGraphicsStateGuardian9::
103 DXGraphicsStateGuardian9(GraphicsEngine *engine, GraphicsPipe *pipe) :
104  GraphicsStateGuardian(CS_yup_left, engine, pipe)
105 {
106  if (dxgsg9_cat.is_debug()) {
107  dxgsg9_cat.debug()
108  << "DXGraphicsStateGuardian9 " << this << " constructing\n";
109  }
110 
111  // Assume that we will get a hardware-accelerated context, unless the window
112  // tells us otherwise.
113  _is_hardware = true;
114 
115  _screen = nullptr;
116  _d3d_device = nullptr;
117 
118  _dx_is_ready = false;
119  _vertex_blending_enabled = false;
120  _overlay_windows_supported = false;
121  _tex_stats_retrieval_impossible = false;
122  _supports_render_texture = false;
123 
124  _active_ibuffer = nullptr;
125 
126  // This is a static member, but we initialize it here in the constructor
127  // anyway. It won't hurt if it gets repeatedly initalized.
128  ZeroMemory(&_d3d_ident_mat, sizeof(D3DMATRIX));
129  _d3d_ident_mat._11 = _d3d_ident_mat._22 = _d3d_ident_mat._33 = _d3d_ident_mat._44 = 1.0f;
130 
131  _cur_read_pixel_buffer = RenderBuffer::T_front;
132 
133  // DirectX drivers seem to consistently invert the texture when they copy
134  // framebuffer-to-texture. Ok.
135  _copy_texture_inverted = true;
136 
137  _gsg_managed_textures = dx_management | dx_texture_management;
138  _gsg_managed_vertex_buffers = dx_management;
139  _gsg_managed_index_buffers = dx_management;
140 
141  _last_fvf = 0;
142  _num_bound_streams = 0;
143  _white_vbuffer = nullptr;
144 
145  _vertex_shader_version_major = 0;
146  _vertex_shader_version_minor = 0;
147  _pixel_shader_version_major = 0;
148  _pixel_shader_version_minor = 0;
149 
150  _vertex_shader_profile = 0;
151  _pixel_shader_profile = 0;
152 
153  _vertex_shader_maximum_constants = 0;
154 
155  _supports_stream_offset = false;
156 
157 #ifdef HAVE_CG
158  _cg_context = 0;
159 #endif
160 
161  get_gamma_table();
162  atexit (atexit_function);
163 }
164 
165 /**
166  *
167  */
168 DXGraphicsStateGuardian9::
169 ~DXGraphicsStateGuardian9() {
170  if (dxgsg9_cat.is_debug()) {
171  dxgsg9_cat.debug()
172  << "DXGraphicsStateGuardian9 " << this << " destructing\n";
173  }
174 
175  if (IS_VALID_PTR(_d3d_device)) {
176  _d3d_device->SetTexture(0, nullptr); // this frees reference to the old texture
177  }
178 
179  free_nondx_resources();
180 }
181 
182 /**
183  * Creates a new retained-mode representation of the given texture, and
184  * returns a newly-allocated TextureContext pointer to reference it. It is
185  * the responsibility of the calling function to later call release_texture()
186  * with this same pointer (which will also delete the pointer).
187  *
188  * This function should not be called directly to prepare a texture. Instead,
189  * call Texture::prepare().
190  */
192 prepare_texture(Texture *tex, int view) {
193  DXTextureContext9 *dtc = new DXTextureContext9(_prepared_objects, tex, view);
194 
196  dxgsg9_cat.error()
197  << *dtc->get_texture() << " is stored in an unsupported compressed format.\n";
198  return nullptr;
199  }
200 
201  return dtc;
202 }
203 
204 /**
205  * Makes the texture the currently available texture for rendering on the ith
206  * stage.
207  */
209 apply_texture(int i, TextureContext *tc, const SamplerState &sampler) {
210  if (tc == nullptr) {
211  // The texture wasn't bound properly or something, so ensure texturing is
212  // disabled and just return.
213  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
214  return;
215  }
216  if (!update_texture(tc, false)) {
217  // Couldn't get the texture image or something.
218  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
219  return;
220  }
221 
222  tc->set_active(true);
223 
224  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
225  Texture *tex = tc->get_texture();
226 
227  // if (tex->get_color_space() == CS_srgb) {
228  if (Texture::is_srgb(tex->get_format())) {
229  set_sampler_state(i, D3DSAMP_SRGBTEXTURE, TRUE);
230  } else {
231  set_sampler_state(i, D3DSAMP_SRGBTEXTURE, FALSE);
232  }
233 
234  set_sampler_state(i, D3DSAMP_ADDRESSU,
235  get_texture_wrap_mode(sampler.get_wrap_u()));
236 
237  set_sampler_state(i, D3DSAMP_ADDRESSV,
238  get_texture_wrap_mode(sampler.get_wrap_v()));
239 
240  set_sampler_state(i, D3DSAMP_ADDRESSW,
241  get_texture_wrap_mode(sampler.get_wrap_w()));
242 
243  DWORD border_color;
244  border_color = LColor_to_D3DCOLOR(sampler.get_border_color());
245 
246  set_sampler_state(i, D3DSAMP_BORDERCOLOR, border_color);
247 
248  uint aniso_degree = sampler.get_effective_anisotropic_degree();
249  SamplerState::FilterType ft = sampler.get_effective_magfilter();
250 
251  if (aniso_degree >= 1) {
252  set_sampler_state(i, D3DSAMP_MAXANISOTROPY, aniso_degree);
253  }
254 
255  int supports_anisotropic_mag_filter;
256  D3DTEXTUREFILTERTYPE new_mag_filter;
257 
258  supports_anisotropic_mag_filter = (_screen -> _d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
259  if (aniso_degree <= 1 || supports_anisotropic_mag_filter == 0) {
260  new_mag_filter = ((ft != SamplerState::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT);
261  } else {
262  new_mag_filter = D3DTEXF_ANISOTROPIC;
263  }
264 
265  HRESULT hr;
266  hr = set_sampler_state(i, D3DSAMP_MAGFILTER, new_mag_filter);
267  if (hr != D3D_OK) {
268  dxgsg9_cat.error()
269  << "ERROR: set_sampler_state (D3DSAMP_MAGFILTER, "
270  << new_mag_filter << ") failed for sampler: " << sampler << endl;
271  }
272 
273  // map Panda composite min+mip filter types to d3d's separate min & mip
274  // filter types
275  D3DTEXTUREFILTERTYPE new_min_filter = get_d3d_min_type(sampler.get_effective_minfilter());
276  D3DTEXTUREFILTERTYPE new_mip_filter = get_d3d_mip_type(sampler.get_effective_minfilter());
277 
278  if (!tex->might_have_ram_image()) {
279  // If the texture is completely dynamic, don't try to issue mipmaps--
280  // pandadx doesn't support auto-generated mipmaps at this point.
281  new_mip_filter = D3DTEXF_NONE;
282  }
283 
284  // sanity check
285  if (!dtc->has_mipmaps()) {
286  new_mip_filter = D3DTEXF_NONE;
287  }
288 
289  if (aniso_degree >= 2) {
290  new_min_filter = D3DTEXF_ANISOTROPIC;
291  }
292 
293  set_sampler_state(i, D3DSAMP_MINFILTER, new_min_filter);
294  set_sampler_state(i, D3DSAMP_MIPFILTER, new_mip_filter);
295 
296  float lod_bias = sampler.get_lod_bias();
297  set_sampler_state(i, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lod_bias);
298 
299  _d3d_device->SetTexture(i, dtc->get_d3d_texture());
300 }
301 
302 /**
303  * Ensures that the current Texture data is refreshed onto the GSG. This
304  * means updating the texture properties and/or re-uploading the texture
305  * image, if necessary. This should only be called within the draw thread.
306  *
307  * If force is true, this function will not return until the texture has been
308  * fully uploaded. If force is false, the function may choose to upload a
309  * simple version of the texture instead, if the texture is not fully resident
310  * (and if get_incomplete_render() is true).
311  */
313 update_texture(TextureContext *tc, bool force) {
314  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
315 
316  // If the texture image has changed, or if its use of mipmaps has changed,
317  // we need to re-create the image.
318 
319  if (dtc->was_modified()) {
320  if (!upload_texture(dtc, force)) {
321  // Oops, we can't re-create the texture for some reason.
322  Texture *tex = tc->get_texture();
323  dxgsg9_cat.error()
324  << "Unable to re-create texture " << *tex << endl;
325  return false;
326  }
327  }
328  dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
329 
330  return true;
331 }
332 
333 /**
334  * Creates a texture surface on the graphics card and fills it with its pixel
335  * data.
336  */
339  Texture *tex = dtc->get_texture();
341  dxgsg9_cat.error()
342  << *tex << " is stored in an unsupported compressed format.\n";
343  return false;
344  }
345 
346  dtc->delete_texture();
347  dtc->update_data_size_bytes(0);
348  dtc->mark_unloaded();
349 
350  if (_effective_incomplete_render && !force) {
351  bool has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image();
352  if (!has_image && tex->might_have_ram_image() &&
353  tex->has_simple_ram_image() &&
354  !_loader.is_null()) {
355  // If we don't have the texture data right now, go get it, but in the
356  // meantime load a temporary simple image in its place.
357  async_reload_texture(dtc);
358  has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image();
359  if (!has_image) {
360  if (dtc->was_simple_image_modified()) {
361  return dtc->create_simple_texture(*_screen);
362  }
363  return true;
364  }
365  }
366  }
367 
368  return dtc->create_texture(*_screen);
369 }
370 
371 /**
372  * Frees the GL resources previously allocated for the texture.
373  */
376  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
377  delete dtc;
378 }
379 
380 /**
381  * This method should only be called by the GraphicsEngine. Do not call it
382  * directly; call GraphicsEngine::extract_texture_data() instead.
383  *
384  * This method will be called in the draw thread to download the texture
385  * memory's image into its ram_image value. It returns true on success, false
386  * otherwise.
387  */
390  bool success = true;
391 
392  int num_views = tex->get_num_views();
393  for (int view = 0; view < num_views; ++view) {
394  TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
395  nassertr(tc != nullptr, false);
396  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
397 
398  if (!dtc->extract_texture_data(*_screen)) {
399  success = false;
400  }
401  }
402 
403  return success;
404 }
405 
406 /**
407  *
408  */
411  PStatTimer timer(_prepare_shader_pcollector);
412 
413  switch (se->get_language()) {
414  case Shader::SL_GLSL:
415  dxgsg9_cat.error()
416  << "Tried to load GLSL shader, but GLSL shaders not supported by Direct3D 9.\n";
417  return nullptr;
418 
419  case Shader::SL_Cg:
420 #ifdef HAVE_CG
421  if (_supports_basic_shaders) {
422  return new DXShaderContext9(se, this);
423  } else {
424  dxgsg9_cat.error()
425  << "Tried to load Cg shader, but basic shaders not supported.\n";
426  return nullptr;
427  }
428 #else
429  dxgsg9_cat.error()
430  << "Tried to load Cg shader, but Cg support not compiled in.\n";
431  return nullptr;
432 #endif
433 
434  default:
435  dxgsg9_cat.error()
436  << "Tried to load shader with unsupported shader language!\n";
437  return nullptr;
438  }
439 
440  return nullptr;
441 }
442 
443 /**
444  *
445  */
448  DXShaderContext9 *gsc = DCAST(DXShaderContext9, sc);
449  delete gsc;
450 }
451 
452 /**
453  * Creates a new retained-mode representation of the given data, and returns a
454  * newly-allocated VertexBufferContext pointer to reference it. It is the
455  * responsibility of the calling function to later call
456  * release_vertex_buffer() with this same pointer (which will also delete the
457  * pointer).
458  *
459  * This function should not be called directly to prepare a buffer. Instead,
460  * call Geom::prepare().
461  */
464  DXVertexBufferContext9 *dvbc = new DXVertexBufferContext9(this, _prepared_objects, data);
465 
466  DWORD usage;
467  D3DPOOL pool;
468  if (_screen->_managed_vertex_buffers) {
469  pool = D3DPOOL_MANAGED;
470  usage = D3DUSAGE_WRITEONLY;
471  } else {
472  pool = D3DPOOL_DEFAULT;
473  usage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC;
474  }
475 
476  int num_bytes = data->get_data_size_bytes();
477 
478  PStatTimer timer(_create_vertex_buffer_pcollector, Thread::get_current_thread());
479 
480  HRESULT hr;
481  int attempts = 0;
482  do
483  {
484  hr = _screen->_d3d_device->CreateVertexBuffer(num_bytes, usage, dvbc->_fvf, pool, &dvbc->_vbuffer, nullptr);
485  attempts++;
486  }
487  while (check_dx_allocation(hr, num_bytes, attempts));
488 
489  if (!FAILED(hr)) {
490  #if 0
491  if (dxgsg9_cat.is_debug() && DXdebug_buffers9) {
492  dxgsg9_cat.debug()
493  << "creating vertex buffer " << dvbc->_vbuffer << ": "
494  << data->get_num_rows() << " vertices "
495  << *data->get_array_format() << "\n";
496  }
497  #endif
498 
499  return dvbc;
500  } else {
501  dxgsg9_cat.error()
502  << "CreateVertexBuffer failed" << D3DERRORSTRING(hr);
503 
504  dvbc->_vbuffer = nullptr;
505  }
506 
507  return nullptr;
508 }
509 
510 /**
511  * Updates the vertex buffer with the current data, and makes it the current
512  * vertex buffer for rendering.
513  */
516  const GeomVertexArrayDataHandle *reader, bool force ) {
517 
519 
520  if (dvbc->was_modified(reader)) {
521  int num_bytes = reader->get_data_size_bytes();
522  #if 0
523  if (dxgsg9_cat.is_debug() && DXdebug_buffers9) {
524  dxgsg9_cat.debug()
525  << "copying " << num_bytes
526  << " bytes into vertex buffer " << dvbc->_vbuffer << "\n";
527  }
528  #endif
529 
530  if ( num_bytes != 0 ) {
531  const unsigned char *client_pointer = reader->get_read_pointer(force);
532  if (client_pointer == nullptr) {
533  return false;
534  }
535 
536  PStatTimer timer(_load_vertex_buffer_pcollector, reader->get_current_thread());
537 
538  #if 0
539  if (dvbc->changed_size(reader)) {
540  // We have to destroy the old vertex buffer and create a new one.
541  dvbc->create_vbuffer(*_screen, reader);
542  }
543  #endif
544 
545  HRESULT hr;
546  BYTE *local_pointer;
547  if (_screen->_managed_vertex_buffers) {
548  hr = dvbc->_vbuffer->Lock(0, num_bytes, (void **) &local_pointer, 0);
549  } else {
550  hr = dvbc->_vbuffer->Lock(0, num_bytes, (void **) &local_pointer, D3DLOCK_DISCARD);
551  }
552  if (FAILED(hr)) {
553  dxgsg9_cat.error()
554  << "VertexBuffer::Lock failed" << D3DERRORSTRING(hr);
555  return false;
556  }
557 
558  memcpy(local_pointer, client_pointer, num_bytes);
559 
560  dvbc->_vbuffer->Unlock();
561 
562  _data_transferred_pcollector.add_level(num_bytes);
563  }
564 
565  dvbc->mark_loaded(reader);
566  }
567  dvbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
568 
569  return true;
570 }
571 
572 /**
573  * Frees the GL resources previously allocated for the data. This function
574  * should never be called directly; instead, call Data::release() (or simply
575  * let the Data destruct).
576  */
579 
581 
582  #if 0
583  if (dxgsg9_cat.is_debug() && DXdebug_buffers9) {
584  dxgsg9_cat.debug()
585  << "deleting vertex buffer " << dvbc->_vbuffer << "\n";
586  }
587  #endif
588 
589  dvbc->_vbuffer->Release();
590  dvbc->_vbuffer = nullptr;
591 
592  delete dvbc;
593 }
594 
595 /**
596  * Internal function to bind a buffer object for the indicated data array, if
597  * appropriate, or to unbind a buffer object if it should be rendered from
598  * client memory.
599  *
600  * If the buffer object is bound, this function sets client_pointer to NULL
601  * (representing the start of the buffer object in server memory); if the
602  * buffer object is not bound, this function sets client_pointer the pointer
603  * to the data array in client memory, that is, the data array passed in.
604  *
605  * If force is not true, the function may return false indicating the data is
606  * not currently available.
607  */
610  const GeomVertexArrayDataHandle* array_reader,
611  bool force) {
612 
613  // Prepare the buffer object and bind it.
614  VertexBufferContext* vbc = ((GeomVertexArrayData *)array_reader->get_object())->prepare_now(get_prepared_objects(), this);
615  nassertr(vbc != nullptr, false);
616  if (!apply_vertex_buffer(vbc, array_reader, force)) {
617  return false;
618  }
619 
620  dvbc = (DXVertexBufferContext9*)vbc;
621  return true;
622 }
623 
624 /**
625  * Creates a new retained-mode representation of the given data, and returns a
626  * newly-allocated IndexBufferContext pointer to reference it. It is the
627  * responsibility of the calling function to later call release_index_buffer()
628  * with this same pointer (which will also delete the pointer).
629  *
630  * This function should not be called directly to prepare a buffer. Instead,
631  * call Geom::prepare().
632  */
635  DXIndexBufferContext9 *dibc = new DXIndexBufferContext9(_prepared_objects, data);
636  return dibc;
637 }
638 
639 /**
640  * Updates the index buffer with the current data, and makes it the current
641  * index buffer for rendering.
642  */
645  const GeomPrimitivePipelineReader *reader, bool force) {
646  DXIndexBufferContext9 *dibc = DCAST(DXIndexBufferContext9, ibc);
647 
648  if (dibc->_ibuffer == nullptr) {
649  // Attempt to create a new index buffer.
650  dibc->create_ibuffer(*_screen, reader);
651 
652  if (dibc->_ibuffer != nullptr) {
653  if (!dibc->upload_data(reader, force)) {
654  return false;
655  }
656  dibc->mark_loaded(reader);
657 
658  _d3d_device->SetIndices(dibc->_ibuffer);
659  _active_ibuffer = dibc;
660  dibc->set_active(true);
661 
662  } else {
663  _d3d_device->SetIndices(nullptr);
664  _active_ibuffer = nullptr;
665  }
666 
667  } else {
668  if (dibc->was_modified(reader)) {
669  if (dibc->changed_size(reader)) {
670  // We have to destroy the old index buffer and create a new one.
671  dibc->create_ibuffer(*_screen, reader);
672  }
673 
674  if (!dibc->upload_data(reader, force)) {
675  return false;
676  }
677 
678  dibc->mark_loaded(reader);
679  _active_ibuffer = nullptr;
680  }
681 
682  if (_active_ibuffer != dibc) {
683  _d3d_device->SetIndices(dibc->_ibuffer);
684  _active_ibuffer = dibc;
685  dibc->set_active(true);
686  }
687  }
688  dibc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
689 
690  return true;
691 }
692 
693 /**
694  * Frees the GL resources previously allocated for the data. This function
695  * should never be called directly; instead, call Data::release() (or simply
696  * let the Data destruct).
697  */
700  DXIndexBufferContext9 *dibc = DCAST(DXIndexBufferContext9, ibc);
701  delete dibc;
702 }
703 
704 /**
705  * Begins a new occlusion query. After this call, you may call
706  * begin_draw_primitives() and draw_triangles()/draw_whatever() repeatedly.
707  * Eventually, you should call end_occlusion_query() before the end of the
708  * frame; that will return a new OcclusionQueryContext object that will tell
709  * you how many pixels represented by the bracketed geometry passed the depth
710  * test.
711  *
712  * It is not valid to call begin_occlusion_query() between another
713  * begin_occlusion_query() .. end_occlusion_query() sequence.
714  */
717  nassertv(_supports_occlusion_query);
718  nassertv(_current_occlusion_query == nullptr);
719 
720  IDirect3DQuery9 *query;
721  HRESULT hr = _d3d_device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query);
722  if (FAILED(hr)) {
723  dxgsg9_cat.warning()
724  << "Occlusion query failed.\n";
725  return;
726  }
727 
728  PT(DXOcclusionQueryContext9) queryobj = new DXOcclusionQueryContext9(query);
729 
730  if (dxgsg9_cat.is_debug()) {
731  dxgsg9_cat.debug()
732  << "beginning occlusion query " << query << "\n";
733  }
734 
735  query->Issue(D3DISSUE_BEGIN);
736  _current_occlusion_query = queryobj;
737 }
738 
739 /**
740  * Ends a previous call to begin_occlusion_query(). This call returns the
741  * OcclusionQueryContext object that will (eventually) report the number of
742  * pixels that passed the depth test between the call to
743  * begin_occlusion_query() and end_occlusion_query().
744  */
745 PT(OcclusionQueryContext) DXGraphicsStateGuardian9::
746 end_occlusion_query() {
747  if (_current_occlusion_query == nullptr) {
748  return nullptr;
749  }
750 
751  PT(OcclusionQueryContext) result = _current_occlusion_query;
752 
753  IDirect3DQuery9 *query = DCAST(DXOcclusionQueryContext9, result)->_query;
754 
755  if (dxgsg9_cat.is_debug()) {
756  dxgsg9_cat.debug()
757  << "ending occlusion query " << query << "\n";
758  }
759 
760  _current_occlusion_query = nullptr;
761  query->Issue(D3DISSUE_END);
762 
763  return result;
764 }
765 
766 /**
767  * Creates a new GeomMunger object to munge vertices appropriate to this GSG
768  * for the indicated state.
769  */
770 PT(GeomMunger) DXGraphicsStateGuardian9::
771 make_geom_munger(const RenderState *state, Thread *current_thread) {
772  PT(DXGeomMunger9) munger = new DXGeomMunger9(this, state);
773  return GeomMunger::register_munger(munger, current_thread);
774 }
775 
776 /**
777  * Clears all of the indicated buffers to their assigned colors.
778  */
780 clear(DrawableRegion *clearable) {
781 
782  DWORD main_flags = 0;
783  DWORD aux_flags = 0;
784 
785  if ((!clearable->get_clear_color_active())&&
786  (!clearable->get_clear_depth_active())&&
787  (!clearable->get_clear_stencil_active())) {
788  return;
789  }
790 
791  set_state_and_transform(RenderState::make_empty(), _internal_transform);
792 
793  D3DCOLOR color_clear_value = LColor_to_D3DCOLOR(clearable->get_clear_color());
794  PN_stdfloat depth_clear_value = clearable->get_clear_depth();
795  DWORD stencil_clear_value = (DWORD)(clearable->get_clear_stencil());
796 
797  // set appropriate flags
798  if (clearable->get_clear_color_active()) {
799  main_flags |= D3DCLEAR_TARGET;
800  }
801 
802  if (clearable->get_clear_depth_active() &&
803  _screen->_presentation_params.EnableAutoDepthStencil) {
804  aux_flags |= D3DCLEAR_ZBUFFER;
805  }
806 
807  if (clearable->get_clear_stencil_active()) {
808  // clear only if there is a stencil buffer
809  if (_screen->_presentation_params.EnableAutoDepthStencil &&
810  IS_STENCIL_FORMAT(_screen->_presentation_params.AutoDepthStencilFormat)) {
811  aux_flags |= D3DCLEAR_STENCIL;
812  }
813  }
814 
815  if ((main_flags | aux_flags) != 0) {
816  HRESULT hr = _d3d_device->Clear(0, nullptr, main_flags | aux_flags, color_clear_value,
817  depth_clear_value, stencil_clear_value);
818  if (FAILED(hr) && main_flags == D3DCLEAR_TARGET && aux_flags != 0) {
819  // Maybe there's a problem with the one or more of the auxiliary
820  // buffers.
821  hr = _d3d_device->Clear(0, nullptr, D3DCLEAR_TARGET, color_clear_value,
822  depth_clear_value, stencil_clear_value);
823  if (!FAILED(hr)) {
824  // Yep, it worked without them. That's a problem. Which buffer poses
825  // the problem?
826  if (clearable->get_clear_depth_active()) {
827  aux_flags |= D3DCLEAR_ZBUFFER;
828  HRESULT hr2 = _d3d_device->Clear(0, nullptr, D3DCLEAR_ZBUFFER, color_clear_value,
829  depth_clear_value, stencil_clear_value);
830  if (FAILED(hr2)) {
831  dxgsg9_cat.error()
832  << "Unable to clear depth buffer; removing.\n";
833  // This is really hacky code.
834  ((FrameBufferProperties *)_current_properties)->set_depth_bits(0);
835  }
836  }
837  if (clearable->get_clear_stencil_active()) {
838  aux_flags |= D3DCLEAR_STENCIL;
839  HRESULT hr2 = _d3d_device->Clear(0, nullptr, D3DCLEAR_STENCIL, color_clear_value,
840  stencil_clear_value, stencil_clear_value);
841  if (FAILED(hr2)) {
842  dxgsg9_cat.error()
843  << "Unable to clear stencil buffer; removing.\n";
844  // This is really hacky code.
845  ((FrameBufferProperties *)_current_properties)->set_stencil_bits(0);
846  _supports_stencil = false;
847  }
848  }
849  }
850  }
851 
852  if (FAILED(hr)) {
853  dxgsg9_cat.error()
854  << "clear_buffer failed: Clear returned " << D3DERRORSTRING(hr);
855  }
856  }
857 }
858 
859 /**
860  * Prepare a display region for rendering (set up scissor region and viewport)
861  */
864  nassertv(dr != nullptr);
866 
867  int l, u, w, h;
868  dr->get_region_pixels_i(l, u, w, h);
869 
870  // Create the viewport
871  D3DVIEWPORT9 vp = { (DWORD)l, (DWORD)u, (DWORD)w, (DWORD)h, 0.0f, 1.0f };
872  _current_viewport = vp;
873  HRESULT hr = _d3d_device->SetViewport(&_current_viewport);
874  if (FAILED(hr)) {
875  dxgsg9_cat.error()
876  << "_screen->_swap_chain = " << _screen->_swap_chain << " _swap_chain = " << _swap_chain << "\n";
877  dxgsg9_cat.error()
878  << "SetViewport(" << l << ", " << u << ", " << w << ", " << h
879  << ") failed" << D3DERRORSTRING(hr);
880 
881  D3DVIEWPORT9 vp_old;
882  _d3d_device->GetViewport(&vp_old);
883  dxgsg9_cat.error()
884  << "GetViewport(" << vp_old.X << ", " << vp_old.Y << ", " << vp_old.Width << ", "
885  << vp_old.Height << ") returned: Trying to set that vp---->\n";
886  hr = _d3d_device->SetViewport(&vp_old);
887  set_render_state(D3DRS_SCISSORTESTENABLE, FALSE);
888 
889  if (FAILED(hr)) {
890  dxgsg9_cat.error() << "Failed again\n";
891  throw_event("panda3d-render-error");
892  nassertv(false);
893  }
894  }
895 
896  if (_screen->_can_direct_disable_color_writes) {
897  set_render_state(D3DRS_COLORWRITEENABLE, _color_write_mask);
898  }
899 }
900 
901 /**
902  * Given a lens, calculates the appropriate projection matrix for use with
903  * this gsg. Note that the projection matrix depends a lot upon the
904  * coordinate system of the rendering API.
905  *
906  * The return value is a TransformState if the lens is acceptable, NULL if it
907  * is not.
908  */
909 CPT(TransformState) DXGraphicsStateGuardian9::
910 calc_projection_mat(const Lens *lens) {
911  if (lens == nullptr) {
912  return nullptr;
913  }
914 
915  if (!lens->is_linear()) {
916  return nullptr;
917  }
918 
919  // DirectX also uses a Z range of 0 to 1, whereas the Panda convention is
920  // for the projection matrix to produce a Z range of -1 to 1. We have to
921  // rescale to compensate.
922  static const LMatrix4 rescale_mat
923  (1, 0, 0, 0,
924  0, 1, 0, 0,
925  0, 0, 0.5, 0,
926  0, 0, 0.5, 1);
927 
928  LMatrix4 result =
929  LMatrix4::convert_mat(CS_yup_left, _current_lens->get_coordinate_system()) *
930  lens->get_projection_mat(_current_stereo_channel) *
931  rescale_mat;
932 
933  if (_scene_setup->get_inverted()) {
934  // If the scene is supposed to be inverted, then invert the projection
935  // matrix.
936  result *= LMatrix4::scale_mat(1.0f, -1.0f, 1.0f);
937  }
938 
939  return TransformState::make_mat(result);
940 }
941 
942 /**
943  * Makes the current lens (whichever lens was most recently specified with
944  * set_scene()) active, so that it will transform future rendered geometry.
945  * Normally this is only called from the draw process, and usually it is
946  * called by set_scene().
947  *
948  * The return value is true if the lens is acceptable, false if it is not.
949  */
952  LMatrix4f mat = LCAST(float, _projection_mat->get_mat());
953  HRESULT hr =
954  _d3d_device->SetTransform(D3DTS_PROJECTION,
955  (D3DMATRIX*)mat.get_data());
956  return SUCCEEDED(hr);
957 }
958 
959 /**
960  * Called before each frame is rendered, to allow the GSG a chance to do any
961  * internal cleanup before beginning the frame.
962  *
963  * The return value is true if successful (in which case the frame will be
964  * drawn and end_frame() will be called later), or false if unsuccessful (in
965  * which case nothing will be drawn and end_frame() will not be called).
966  */
968 begin_frame(Thread *current_thread) {
969 
970  GraphicsStateGuardian::begin_frame(current_thread);
971 
972  if (_d3d_device == nullptr) {
973  dxgsg9_cat.debug()
974  << this << "::begin_frame(): no device.\n";
975  return false;
976  }
977 
978  HRESULT hr = _d3d_device->BeginScene();
979 
980  if (FAILED(hr)) {
981  if (hr == D3DERR_DEVICELOST) {
982  if (dxgsg9_cat.is_debug()) {
983  dxgsg9_cat.debug()
984  << "BeginScene returns D3DERR_DEVICELOST" << endl;
985  }
986 
987  check_cooperative_level();
988 
989  } else {
990  dxgsg9_cat.error()
991  << "BeginScene failed, unhandled error hr == "
992  << D3DERRORSTRING(hr) << endl;
993  throw_event("panda3d-render-error");
994  }
995  return false;
996  }
997 
998  if (_current_properties->get_srgb_color()) {
999  set_render_state(D3DRS_SRGBWRITEENABLE, TRUE);
1000  } else {
1001  set_render_state(D3DRS_SRGBWRITEENABLE, FALSE);
1002  }
1003 
1004  return true;
1005 }
1006 
1007 /**
1008  * Called between begin_frame() and end_frame() to mark the beginning of
1009  * drawing commands for a "scene" (usually a particular DisplayRegion) within
1010  * a frame. All 3-D drawing commands, except the clear operation, must be
1011  * enclosed within begin_scene() .. end_scene().
1012  *
1013  * The return value is true if successful (in which case the scene will be
1014  * drawn and end_scene() will be called later), or false if unsuccessful (in
1015  * which case nothing will be drawn and end_scene() will not be called).
1016  */
1020  return false;
1021  }
1022 
1023 /*
1024  HRESULT hr = _d3d_device->BeginScene();
1025 
1026  if (FAILED(hr)) {
1027  if (hr == D3DERR_DEVICELOST) {
1028  if (dxgsg9_cat.is_debug()) {
1029  dxgsg9_cat.debug()
1030  << "BeginScene returns D3DERR_DEVICELOST" << endl;
1031  }
1032 
1033  check_cooperative_level();
1034 
1035  } else {
1036  dxgsg9_cat.error()
1037  << "BeginScene failed, unhandled error hr == "
1038  << D3DERRORSTRING(hr) << endl;
1039  throw_event("panda3d-render-error");
1040  }
1041  return false;
1042  }
1043 */
1044 
1045  return true;
1046 }
1047 
1048 /**
1049  * Called between begin_frame() and end_frame() to mark the end of drawing
1050  * commands for a "scene" (usually a particular DisplayRegion) within a frame.
1051  * All 3-D drawing commands, except the clear operation, must be enclosed
1052  * within begin_scene() .. end_scene().
1053  */
1057 
1058  if (_vertex_array_shader_context != 0) {
1059  _vertex_array_shader_context->disable_shader_vertex_arrays(this);
1060  _vertex_array_shader = nullptr;
1061  _vertex_array_shader_context = nullptr;
1062  }
1063  if (_texture_binding_shader_context != 0) {
1064  _texture_binding_shader_context->disable_shader_texture_bindings(this);
1065  _texture_binding_shader = nullptr;
1066  _texture_binding_shader_context = nullptr;
1067  }
1068  if (_current_shader_context != 0) {
1069  _current_shader_context->unbind(this);
1070  _current_shader = nullptr;
1071  _current_shader_context = nullptr;
1072  }
1073 
1074  _dlights.clear();
1075 
1076 /*
1077  HRESULT hr = _d3d_device->EndScene();
1078 
1079  if (FAILED(hr)) {
1080  if (hr == D3DERR_DEVICELOST) {
1081  if (dxgsg9_cat.is_debug()) {
1082  dxgsg9_cat.debug()
1083  << "EndScene returns DeviceLost\n";
1084  }
1085  check_cooperative_level();
1086 
1087  } else {
1088  dxgsg9_cat.error()
1089  << "EndScene failed, unhandled error hr == " << D3DERRORSTRING(hr);
1090  throw_event("panda3d-render-error");
1091  }
1092  return;
1093  }
1094 */
1095 
1096 }
1097 
1098 /**
1099  * Called after each frame is rendered, to allow the GSG a chance to do any
1100  * internal cleanup after rendering the frame, and before the window flips.
1101  */
1103 end_frame(Thread *current_thread) {
1104 
1105  HRESULT hr = _d3d_device->EndScene();
1106 
1107  if (FAILED(hr)) {
1108  if (hr == D3DERR_DEVICELOST) {
1109  if (dxgsg9_cat.is_debug()) {
1110  dxgsg9_cat.debug()
1111  << "EndScene returns DeviceLost\n";
1112  }
1113  check_cooperative_level();
1114 
1115  } else {
1116  dxgsg9_cat.error()
1117  << "EndScene failed, unhandled error hr == " << D3DERRORSTRING(hr);
1118  throw_event("panda3d-render-error");
1119  }
1120  return;
1121  }
1122 
1123 #if defined(DO_PSTATS)
1124  if (_texmgrmem_total_pcollector.is_active()) {
1125 #define TICKS_PER_GETTEXINFO (2.5*1000) // 2.5 second interval
1126  static DWORD last_tick_count = 0;
1127  DWORD cur_tick_count = GetTickCount();
1128 
1129  if (cur_tick_count - last_tick_count > TICKS_PER_GETTEXINFO) {
1130  last_tick_count = cur_tick_count;
1131  report_texmgr_stats();
1132  }
1133  }
1134 #endif
1135 
1136  // Note: regular GraphicsWindow::end_frame is being called, but we override
1137  // gsg::end_frame, so need to explicitly call it here (currently it's an
1138  // empty fn)
1139  GraphicsStateGuardian::end_frame(current_thread);
1140 }
1141 
1142 /**
1143  * Called before a sequence of draw_primitive() functions are called, this
1144  * should prepare the vertex data for rendering. It returns true if the
1145  * vertices are ok, false to abort this group of primitives.
1146  */
1149  const GeomVertexDataPipelineReader *data_reader,
1150  bool force) {
1151  if (!GraphicsStateGuardian::begin_draw_primitives(geom_reader, data_reader, force)) {
1152  return false;
1153  }
1154  nassertr(_data_reader != nullptr, false);
1155 
1156  const GeomVertexFormat *format = _data_reader->get_format();
1157 
1158  const GeomVertexAnimationSpec &animation =
1159  data_reader->get_format()->get_animation();
1160  if (animation.get_animation_type() == Geom::AT_hardware) {
1161  // Set up vertex blending.
1162  switch (animation.get_num_transforms()) {
1163  case 1:
1164  // The MSDN docs suggest we should use D3DVBF_0WEIGHTS here, but that
1165  // doesn't seem to work at all. On the other hand, D3DVBF_DISABLE
1166  // *does* work, because it disables special handling, meaning only the
1167  // world matrix affects these vertices--and by accident or design, the
1168  // first matrix, D3DTS_WORLDMATRIX(0), *is* the world matrix.
1169  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
1170  break;
1171  case 2:
1172  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS);
1173  break;
1174  case 3:
1175  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_2WEIGHTS);
1176  break;
1177  case 4:
1178  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_3WEIGHTS);
1179  break;
1180  }
1181 
1182  if (animation.get_indexed_transforms()) {
1183  // Set up indexed vertex blending.
1184  set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE);
1185  } else {
1186  set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
1187  }
1188 
1189  const TransformTable *table = data_reader->get_transform_table();
1190  if (table != nullptr) {
1191  for (size_t i = 0; i < table->get_num_transforms(); ++i) {
1192  LMatrix4 mat;
1193  table->get_transform(i)->mult_matrix(mat, _internal_transform->get_mat());
1194  const D3DMATRIX *d3d_mat = (const D3DMATRIX *)mat.get_data();
1195  _d3d_device->SetTransform(D3DTS_WORLDMATRIX(i), d3d_mat);
1196  }
1197 
1198  // Setting the first animation matrix steps on the world matrix, so we
1199  // have to set a flag to reload the world matrix later.
1200  _transform_stale = true;
1201  }
1202  _vertex_blending_enabled = true;
1203 
1204  } else {
1205  // We're not using vertex blending.
1206  if (_vertex_blending_enabled) {
1207  set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
1208  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
1209  _vertex_blending_enabled = false;
1210  }
1211 
1212  if (_transform_stale && !_data_reader->is_vertex_transformed()) {
1213  const D3DMATRIX *d3d_mat = (const D3DMATRIX *)_internal_transform->get_mat().get_data();
1214  _d3d_device->SetTransform(D3DTS_WORLD, d3d_mat);
1215  _transform_stale = false;
1216  }
1217  }
1218 
1219  if (_data_reader->is_vertex_transformed()) {
1220  // If the vertex data claims to be already transformed into clip
1221  // coordinates, wipe out the current projection and modelview matrix (so
1222  // we don't attempt to transform it again).
1223 
1224  // It's tempting just to use the D3DFVF_XYZRHW specification on these
1225  // vertices, but that turns out to be a bigger hammer than we want: that
1226  // also prevents lighting calculations and user clip planes.
1227  _d3d_device->SetTransform(D3DTS_WORLD, &_d3d_ident_mat);
1228  static const LMatrix4f rescale_mat
1229  (1, 0, 0, 0,
1230  0, 1, 0, 0,
1231  0, 0, 0.5, 0,
1232  0, 0, 0.5, 1);
1233  _transform_stale = true;
1234 
1235  _d3d_device->SetTransform(D3DTS_PROJECTION, (const D3DMATRIX *)rescale_mat.get_data());
1236  }
1237 
1238  if (_current_shader_context == 0 /*|| !_current_shader_context->uses_custom_vertex_arrays()*/) {
1239  // No shader, or a non-Cg shader.
1240  if (_vertex_array_shader_context != 0) {
1241  _vertex_array_shader_context->disable_shader_vertex_arrays(this);
1242  }
1243  if (!update_standard_vertex_arrays(force)) {
1244  return false;
1245  }
1246  } else {
1247  // Cg shader.
1248  if (_vertex_array_shader_context == 0) {
1249  disable_standard_vertex_arrays();
1250  if (!_current_shader_context->update_shader_vertex_arrays(nullptr, this, force)) {
1251  return false;
1252  }
1253  } else {
1254  if (!_current_shader_context->
1255  update_shader_vertex_arrays(_vertex_array_shader_context, this, force)) {
1256  return false;
1257  }
1258  }
1259  }
1260 
1261  _vertex_array_shader = _current_shader;
1262  _vertex_array_shader_context = _current_shader_context;
1263 
1264  return true;
1265 }
1266 
1267 /**
1268  * Binds vertex buffers as stream sources and sets the correct FVF format for
1269  * fixed-function rendering. Used only when the standard (non-shader)
1270  * pipeline is about to be used - dxShaderContexts are responsible for setting
1271  * up their own vertex arrays.
1272  */
1273 bool DXGraphicsStateGuardian9::
1274 update_standard_vertex_arrays(bool force) {
1275 
1276  int fvf = 0;
1277  HRESULT hr;
1278 
1279  int number_of_arrays = _data_reader->get_num_arrays();
1280  for ( int array_index = 0; array_index < number_of_arrays; ++array_index ) {
1281  const GeomVertexArrayDataHandle* array_reader = _data_reader->get_array_reader( array_index );
1282  if ( array_reader == nullptr ) {
1283  dxgsg9_cat.error() << "Unable to get reader for array " << array_index << "\n";
1284  return false;
1285  }
1286 
1287  // Get the vertex buffer for this array.
1288  DXVertexBufferContext9* dvbc;
1289  if (!setup_array_data(dvbc, array_reader, force)) {
1290  dxgsg9_cat.error() << "Unable to setup vertex buffer for array " << array_index << "\n";
1291  return false;
1292  }
1293 
1294  // Bind this array as the data source for the corresponding stream.
1295  const GeomVertexArrayFormat* array_format = array_reader->get_array_format();
1296  hr = _d3d_device->SetStreamSource( array_index, dvbc->_vbuffer, 0, array_format->get_stride() );
1297  if (FAILED(hr)) {
1298  dxgsg9_cat.error() << "SetStreamSource failed" << D3DERRORSTRING(hr);
1299  return false;
1300  }
1301 
1302  // Update our combined set of FVF flags
1303  fvf |= dvbc->_fvf;
1304  }
1305 
1306  hr = _d3d_device->SetFVF( fvf );
1307  if (FAILED(hr)) {
1308  dxgsg9_cat.error() << "SetFVF failed" << D3DERRORSTRING(hr);
1309  return false;
1310  }
1311 
1312  return true;
1313 }
1314 
1315 /**
1316  * Unbinds all of the streams that are currently enabled. dxShaderContexts
1317  * are responsible for setting up their own streams, but before they can do
1318  * so, the standard streams need to be disabled to get them "out of the way."
1319  * Called only from begin_draw_primitives.
1320  */
1321 void DXGraphicsStateGuardian9::
1322 disable_standard_vertex_arrays() {
1323  for ( int array_index = 0; array_index < _num_bound_streams; ++array_index )
1324  {
1325  _d3d_device->SetStreamSource( array_index, nullptr, 0, 0 );
1326  }
1327  _num_bound_streams = 0;
1328 }
1329 
1330 /**
1331  * Draws a series of disconnected triangles.
1332  */
1334 draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
1335  // PStatTimer timer(_draw_primitive_pcollector);
1336 
1337  _vertices_tri_pcollector.add_level(reader->get_num_vertices());
1338  _primitive_batches_tri_pcollector.add_level(1);
1339 
1340  if (reader->is_indexed()) {
1341  int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
1342  int max_vertex = reader->get_max_vertex();
1343 
1344  // Indexed, vbuffers.
1345  IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
1346  nassertr(ibc != nullptr, false);
1347  if (!apply_index_buffer(ibc, reader, force)) {
1348  return false;
1349  }
1350 
1351  _d3d_device->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,
1352  0,
1353  min_vertex, max_vertex - min_vertex + 1,
1354  0, reader->get_num_primitives() );
1355 
1356  #if 0
1357  // Indexed, client arrays.
1358  const unsigned char *index_pointer = reader->get_read_pointer(force);
1359  if (index_pointer == nullptr) {
1360  return false;
1361  }
1362  D3DFORMAT index_type = get_index_type(reader->get_index_type());
1363  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1364  if (vertex_pointer == nullptr) {
1365  return false;
1366  }
1367 
1368  draw_indexed_primitive_up( D3DPT_TRIANGLELIST,
1369  min_vertex, max_vertex,
1370  reader->get_num_primitives(),
1371  index_pointer, index_type, vertex_pointer,
1372  _data_reader->get_format()->get_array(0)->get_stride() );
1373  #endif
1374  } else {
1375  // Nonindexed, vbuffers.
1376  _d3d_device->DrawPrimitive( D3DPT_TRIANGLELIST,
1377  reader->get_first_vertex(),
1378  reader->get_num_primitives() );
1379 
1380  #if 0
1381  // Nonindexed, client arrays.
1382  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1383  if (vertex_pointer == nullptr) {
1384  return false;
1385  }
1386 
1387  draw_primitive_up(D3DPT_TRIANGLELIST, reader->get_num_primitives(),
1388  reader->get_first_vertex(),
1389  reader->get_num_vertices(), vertex_pointer,
1390  _data_reader->get_format()->get_array(0)->get_stride());
1391  #endif
1392  }
1393 
1394  return true;
1395 }
1396 
1397 /**
1398  * Draws a series of triangle strips.
1399  */
1401 draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
1402  // PStatTimer timer(_draw_primitive_pcollector);
1403 
1404  if (connect_triangle_strips && _current_fill_mode != RenderModeAttrib::M_wireframe) {
1405  // One long triangle strip, connected by the degenerate vertices that have
1406  // already been set up within the primitive.
1407  _vertices_tristrip_pcollector.add_level(reader->get_num_vertices());
1408  _primitive_batches_tristrip_pcollector.add_level(1);
1409 
1410  if (reader->is_indexed()) {
1411  int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
1412  int max_vertex = reader->get_max_vertex();
1413 
1414  // Indexed, vbuffers, one long triangle strip.
1415  IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
1416  nassertr(ibc != nullptr, false);
1417  if (!apply_index_buffer(ibc, reader, force)) {
1418  return false;
1419  }
1420 
1421  _d3d_device->DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP,
1422  0,
1423  min_vertex, max_vertex - min_vertex + 1,
1424  0, reader->get_num_vertices() - 2 );
1425 
1426  #if 0
1427  // Indexed, client arrays, one long triangle strip.
1428  const unsigned char *index_pointer = reader->get_read_pointer(force);
1429  if (index_pointer == nullptr) {
1430  return false;
1431  }
1432  D3DFORMAT index_type = get_index_type(reader->get_index_type());
1433  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1434  if (vertex_pointer == nullptr) {
1435  return false;
1436  }
1437 
1438  draw_indexed_primitive_up
1439  (D3DPT_TRIANGLESTRIP,
1440  min_vertex, max_vertex,
1441  reader->get_num_vertices() - 2,
1442  index_pointer, index_type, vertex_pointer,
1443  _data_reader->get_format()->get_array(0)->get_stride());
1444  #endif
1445  } else {
1446  // Nonindexed, vbuffers, one long triangle strip.
1447  _d3d_device->DrawPrimitive( D3DPT_TRIANGLESTRIP,
1448  reader->get_first_vertex(),
1449  reader->get_num_vertices() - 2 );
1450 
1451  #if 0
1452  // Indexed, client arrays, one long triangle strip.
1453  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1454  if (vertex_pointer == nullptr) {
1455  return false;
1456  }
1457  draw_primitive_up(D3DPT_TRIANGLESTRIP,
1458  reader->get_num_vertices() - 2,
1459  reader->get_first_vertex(),
1460  reader->get_num_vertices(), vertex_pointer,
1461  _data_reader->get_format()->get_array(0)->get_stride());
1462  #endif
1463  }
1464 
1465  } else {
1466  // Send the individual triangle strips, stepping over the degenerate
1467  // vertices.
1468  CPTA_int ends = reader->get_ends();
1469  _primitive_batches_tristrip_pcollector.add_level(ends.size());
1470 
1471  if (reader->is_indexed()) {
1472  CPTA_int ends = reader->get_ends();
1473  int index_stride = reader->get_index_stride();
1474  _primitive_batches_tristrip_pcollector.add_level(ends.size());
1475 
1476  GeomVertexReader mins(reader->get_mins(), 0);
1477  GeomVertexReader maxs(reader->get_maxs(), 0);
1478  nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
1479  reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
1480 
1481  // Indexed, vbuffers, individual triangle strips.
1482  IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
1483  nassertr(ibc != nullptr, false);
1484  if (!apply_index_buffer(ibc, reader, force)) {
1485  return false;
1486  }
1487 
1488  unsigned int start = 0;
1489  for (size_t i = 0; i < ends.size(); i++) {
1490  _vertices_tristrip_pcollector.add_level(ends[i] - start);
1491  unsigned int min = mins.get_data1i();
1492  unsigned int max = maxs.get_data1i();
1493  _d3d_device->DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP,
1494  0,
1495  min, max - min + 1,
1496  start, ends[i] - start - 2 );
1497  start = ends[i] + 2;
1498  }
1499 
1500  #if 0
1501  // Indexed, client arrays, individual triangle strips.
1502  int stride = _data_reader->get_format()->get_array(0)->get_stride();
1503  const unsigned char *index_pointer = reader->get_read_pointer(force);
1504  if (index_pointer == nullptr) {
1505  return false;
1506  }
1507  D3DFORMAT index_type = get_index_type(reader->get_index_type());
1508  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1509  if (vertex_pointer == nullptr) {
1510  return false;
1511  }
1512 
1513  unsigned int start = 0;
1514  for (size_t i = 0; i < ends.size(); i++) {
1515  _vertices_tristrip_pcollector.add_level(ends[i] - start);
1516  unsigned int min = mins.get_data1i();
1517  unsigned int max = maxs.get_data1i();
1518  draw_indexed_primitive_up
1519  (D3DPT_TRIANGLESTRIP,
1520  min, max,
1521  ends[i] - start - 2,
1522  index_pointer + start * index_stride, index_type,
1523  vertex_pointer, stride);
1524 
1525  start = ends[i] + 2;
1526  }
1527  #endif
1528  } else {
1529  unsigned int first_vertex = reader->get_first_vertex();
1530 
1531  // Nonindexed, vbuffers, individual triangle strips.
1532  unsigned int start = 0;
1533  for (size_t i = 0; i < ends.size(); i++) {
1534  _vertices_tristrip_pcollector.add_level(ends[i] - start);
1535  _d3d_device->DrawPrimitive( D3DPT_TRIANGLESTRIP,
1536  first_vertex + start,
1537  ends[i] - start - 2 );
1538  start = ends[i] + 2;
1539  }
1540 
1541  #if 0
1542  // Nonindexed, client arrays, individual triangle strips.
1543  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1544  if (vertex_pointer == nullptr) {
1545  return false;
1546  }
1547  int stride = _data_reader->get_format()->get_array(0)->get_stride();
1548 
1549  unsigned int start = 0;
1550  for (size_t i = 0; i < ends.size(); i++) {
1551  _vertices_tristrip_pcollector.add_level(ends[i] - start);
1552  draw_primitive_up(D3DPT_TRIANGLESTRIP, ends[i] - start - 2,
1553  first_vertex + start,
1554  ends[i] - start,
1555  vertex_pointer, stride);
1556 
1557  start = ends[i] + 2;
1558  }
1559  #endif
1560  }
1561  }
1562  return true;
1563 }
1564 
1565 /**
1566  * Draws a series of triangle fans.
1567  */
1569 draw_trifans(const GeomPrimitivePipelineReader *reader, bool force) {
1570  // PStatTimer timer(_draw_primitive_pcollector);
1571 
1572  CPTA_int ends = reader->get_ends();
1573  _primitive_batches_trifan_pcollector.add_level(ends.size());
1574 
1575  if (reader->is_indexed()) {
1576  int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
1577  int max_vertex = reader->get_max_vertex();
1578 
1579  // Send the individual triangle fans. There's no connecting fans with
1580  // degenerate vertices, so no worries about that.
1581  int index_stride = reader->get_index_stride();
1582 
1583  GeomVertexReader mins(reader->get_mins(), 0);
1584  GeomVertexReader maxs(reader->get_maxs(), 0);
1585  nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
1586  reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
1587 
1588  // Indexed, vbuffers.
1589  IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
1590  nassertr(ibc != nullptr, false);
1591  if (!apply_index_buffer(ibc, reader, force)) {
1592  return false;
1593  }
1594 
1595  unsigned int start = 0;
1596  for (size_t i = 0; i < ends.size(); i++) {
1597  _vertices_trifan_pcollector.add_level(ends[i] - start);
1598  unsigned int min = mins.get_data1i();
1599  unsigned int max = maxs.get_data1i();
1600  _d3d_device->DrawIndexedPrimitive( D3DPT_TRIANGLEFAN,
1601  0,
1602  min, max - min + 1,
1603  start, ends[i] - start - 2 );
1604  start = ends[i];
1605  }
1606 
1607  #if 0
1608  // Indexed, client arrays.
1609  int stride = _data_reader->get_format()->get_array(0)->get_stride();
1610  const unsigned char *index_pointer = reader->get_read_pointer(force);
1611  if (index_pointer == nullptr) {
1612  return false;
1613  }
1614  D3DFORMAT index_type = get_index_type(reader->get_index_type());
1615  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1616  if (vertex_pointer == nullptr) {
1617  return false;
1618  }
1619 
1620  unsigned int start = 0;
1621  for (size_t i = 0; i < ends.size(); i++) {
1622  _vertices_trifan_pcollector.add_level(ends[i] - start);
1623  unsigned int min = mins.get_data1i();
1624  unsigned int max = maxs.get_data1i();
1625  draw_indexed_primitive_up
1626  (D3DPT_TRIANGLEFAN,
1627  min, max,
1628  ends[i] - start - 2,
1629  index_pointer + start * index_stride, index_type,
1630  vertex_pointer, stride);
1631 
1632  start = ends[i];
1633  }
1634  #endif
1635  } else {
1636  unsigned int first_vertex = reader->get_first_vertex();
1637 
1638  // Nonindexed, vbuffers.
1639  unsigned int start = 0;
1640  for (size_t i = 0; i < ends.size(); i++) {
1641  _vertices_trifan_pcollector.add_level(ends[i] - start);
1642  _d3d_device->DrawPrimitive( D3DPT_TRIANGLEFAN,
1643  first_vertex + start,
1644  ends[i] - start - 2 );
1645  start = ends[i];
1646  }
1647 
1648  #if 0
1649  // Nonindexed, client arrays.
1650  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1651  if (vertex_pointer == nullptr) {
1652  return false;
1653  }
1654  int stride = _data_reader->get_format()->get_array(0)->get_stride();
1655 
1656  unsigned int start = 0;
1657  for (size_t i = 0; i < ends.size(); i++) {
1658  _vertices_trifan_pcollector.add_level(ends[i] - start);
1659  draw_primitive_up(D3DPT_TRIANGLEFAN,
1660  ends[i] - start - 2,
1661  first_vertex,
1662  ends[i] - start,
1663  vertex_pointer, stride);
1664  start = ends[i];
1665  }
1666  #endif
1667  }
1668  return true;
1669 }
1670 
1671 /**
1672  * Draws a series of disconnected line segments.
1673  */
1675 draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
1676  // PStatTimer timer(_draw_primitive_pcollector);
1677 
1678  _vertices_other_pcollector.add_level(reader->get_num_vertices());
1679  _primitive_batches_other_pcollector.add_level(1);
1680 
1681  if (reader->is_indexed()) {
1682  int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
1683  int max_vertex = reader->get_max_vertex();
1684 
1685  // Indexed, vbuffers.
1686  IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
1687  nassertr(ibc != nullptr, false);
1688  if (!apply_index_buffer(ibc, reader, force)) {
1689  return false;
1690  }
1691 
1692  _d3d_device->DrawIndexedPrimitive( D3DPT_LINELIST,
1693  0,
1694  min_vertex, max_vertex - min_vertex + 1,
1695  0, reader->get_num_primitives() );
1696 
1697  #if 0
1698  // Indexed, client arrays.
1699  const unsigned char *index_pointer = reader->get_read_pointer(force);
1700  if (index_pointer == nullptr) {
1701  return false;
1702  }
1703  D3DFORMAT index_type = get_index_type(reader->get_index_type());
1704  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1705  if (vertex_pointer == nullptr) {
1706  return false;
1707  }
1708 
1709  draw_indexed_primitive_up
1710  (D3DPT_LINELIST,
1711  min_vertex, max_vertex,
1712  reader->get_num_primitives(),
1713  index_pointer, index_type, vertex_pointer,
1714  _data_reader->get_format()->get_array(0)->get_stride());
1715  #endif
1716  } else {
1717  // Nonindexed, vbuffers.
1718  _d3d_device->DrawPrimitive( D3DPT_LINELIST,
1719  reader->get_first_vertex(),
1720  reader->get_num_primitives() );
1721 
1722  #if 0
1723  // Nonindexed, client arrays.
1724  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1725  if (vertex_pointer == nullptr) {
1726  return false;
1727  }
1728  draw_primitive_up(D3DPT_LINELIST, reader->get_num_primitives(),
1729  reader->get_first_vertex(),
1730  reader->get_num_vertices(), vertex_pointer,
1731  _data_reader->get_format()->get_array(0)->get_stride());
1732  #endif
1733  }
1734  return true;
1735 }
1736 
1737 /**
1738  * Draws a series of line strips.
1739  */
1741 draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force) {
1742  return false;
1743 }
1744 
1745 /**
1746  * Draws a series of disconnected points.
1747  */
1749 draw_points(const GeomPrimitivePipelineReader *reader, bool force) {
1750  // PStatTimer timer(_draw_primitive_pcollector);
1751 
1752  _vertices_other_pcollector.add_level(reader->get_num_vertices());
1753  _primitive_batches_other_pcollector.add_level(1);
1754 
1755  // The munger should have protected us from indexed points--DirectX doesn't
1756  // support them.
1757  nassertr(!reader->is_indexed(), false);
1758 
1759  // Nonindexed, vbuffers.
1760  _d3d_device->DrawPrimitive( D3DPT_POINTLIST,
1761  reader->get_first_vertex(),
1762  reader->get_num_primitives() );
1763 
1764  #if 0
1765  // Nonindexed, client arrays.
1766  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1767  if (vertex_pointer == nullptr) {
1768  return false;
1769  }
1770  draw_primitive_up(D3DPT_POINTLIST, reader->get_num_primitives(),
1771  reader->get_first_vertex(),
1772  reader->get_num_vertices(), vertex_pointer,
1773  _data_reader->get_format()->get_array(0)->get_stride());
1774  #endif
1775 
1776  return true;
1777 }
1778 
1779 /**
1780  * Called after a sequence of draw_primitive() functions are called, this
1781  * should do whatever cleanup is appropriate.
1782  */
1785  // Turn off vertex blending--it seems to cause problems if we leave it on.
1786  if (_vertex_blending_enabled) {
1787  set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
1788  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
1789  _vertex_blending_enabled = false;
1790  }
1791 
1792  if (_data_reader->is_vertex_transformed()) {
1793  // Restore the projection matrix that we wiped out above.
1794  LMatrix4f mat = LCAST(float, _projection_mat->get_mat());
1795  _d3d_device->SetTransform(D3DTS_PROJECTION,
1796  (D3DMATRIX*)mat.get_data());
1797  }
1798 
1800 }
1801 
1802 /**
1803  * Copy the pixels within the indicated display region from the framebuffer
1804  * into texture memory.
1805  *
1806  * If z > -1, it is the cube map index into which to copy.
1807  */
1809 framebuffer_copy_to_texture(Texture *tex, int view, int z,
1810  const DisplayRegion *dr, const RenderBuffer &rb) {
1811  set_read_buffer(rb);
1812 
1813  int orig_x = tex->get_x_size();
1814  int orig_y = tex->get_y_size();
1815 
1816  HRESULT hr;
1817  int xo, yo, w, h;
1818  dr->get_region_pixels_i(xo, yo, w, h);
1819  tex->set_size_padded(w, h);
1820 
1821  // must use a render target type texture for StretchRect
1822  tex->set_render_to_texture(true);
1823 
1824  TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
1825  if (tc == nullptr) {
1826  return false;
1827  }
1828  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
1829  if (!dtc->create_texture(*_screen)) {
1830  // Oops, we can't re-create the texture for some reason.
1831  dxgsg9_cat.error()
1832  << "Unable to re-create texture " << *dtc->get_texture() << endl;
1833  return false;
1834  }
1835 
1836  if (tex->get_texture_type() != Texture::TT_2d_texture) {
1837  // For a specialty texture like a cube map, go the slow route through RAM
1838  // for now.
1839  return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, true);
1840  }
1841  nassertr(dtc->get_d3d_2d_texture() != nullptr, false);
1842 
1843  IDirect3DSurface9 *tex_level_0;
1844  hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
1845  if (FAILED(hr)) {
1846  dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
1847  return false;
1848  }
1849 
1850  // If the texture is the wrong size, we need to do something about it.
1851  D3DSURFACE_DESC texdesc;
1852  hr = tex_level_0->GetDesc(&texdesc);
1853  if (FAILED(hr)) {
1854  dxgsg9_cat.error() << "GetDesc failed in copy_texture" << D3DERRORSTRING(hr);
1855  SAFE_RELEASE(tex_level_0);
1856  return false;
1857  }
1858  if ((texdesc.Width != tex->get_x_size())||(texdesc.Height != tex->get_y_size())) {
1859  if ((orig_x != tex->get_x_size()) || (orig_y != tex->get_y_size())) {
1860  // Texture might be wrong size because we resized it and need to
1861  // recreate.
1862  SAFE_RELEASE(tex_level_0);
1863  if (!dtc->create_texture(*_screen)) {
1864  // Oops, we can't re-create the texture for some reason.
1865  dxgsg9_cat.error()
1866  << "Unable to re-create texture " << *dtc->get_texture() << endl;
1867  return false;
1868  }
1869  hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
1870  if (FAILED(hr)) {
1871  dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
1872  return false;
1873  }
1874  hr = tex_level_0->GetDesc(&texdesc);
1875  if (FAILED(hr)) {
1876  dxgsg9_cat.error() << "GetDesc 2 failed in copy_texture" << D3DERRORSTRING(hr);
1877  SAFE_RELEASE(tex_level_0);
1878  return false;
1879  }
1880  }
1881  if ((texdesc.Width != tex->get_x_size())||(texdesc.Height != tex->get_y_size())) {
1882  // If it's still the wrong size, it's because driver can't create size
1883  // that we want. In that case, there's no helping it, we have to give
1884  // up.
1885  dxgsg9_cat.error()
1886  << "Unable to copy to texture, texture is wrong size: " << *dtc->get_texture() << endl;
1887  SAFE_RELEASE(tex_level_0);
1888  return false;
1889  }
1890  }
1891 
1892  DWORD render_target_index;
1893  IDirect3DSurface9 *render_target;
1894 
1895  /* ***** DX9 GetRenderTarget, assume only one render target so index = 0 */
1896  render_target_index = 0;
1897 
1898  hr = _d3d_device->GetRenderTarget(render_target_index, &render_target);
1899  if (FAILED(hr)) {
1900  dxgsg9_cat.error()
1901  << "GetRenderTarget failed in framebuffer_copy_to_texture"
1902  << D3DERRORSTRING(hr);
1903  SAFE_RELEASE(tex_level_0);
1904  return false;
1905  }
1906 
1907  RECT src_rect;
1908 
1909  src_rect.left = xo;
1910  src_rect.right = xo+w;
1911  src_rect.top = yo;
1912  src_rect.bottom = yo+h;
1913 
1914 // THE DX8 WAY hr = _d3d_device->CopyRects(render_target, &src_rect, 1,
1915 // tex_level_0, 0);
1916 
1917 // DX9
1918  D3DTEXTUREFILTERTYPE filter;
1919 
1920  filter = D3DTEXF_POINT;
1921 
1922  bool okflag = true;
1923  hr = _d3d_device->StretchRect(render_target, &src_rect,
1924  tex_level_0, &src_rect,
1925  filter);
1926  if (FAILED(hr)) {
1927  dxgsg9_cat.debug()
1928  << "StretchRect failed in framebuffer_copy_to_texture"
1929  << D3DERRORSTRING(hr);
1930  okflag = false;
1931  }
1932 
1933  SAFE_RELEASE(render_target);
1934  SAFE_RELEASE(tex_level_0);
1935 
1936  if (okflag) {
1937  dtc->mark_loaded();
1938  dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
1939 
1940  } else {
1941  // The copy failed. Fall back to copying it to RAM and back. Terribly
1942  // slow, but what are you going to do?
1943  return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, true);
1944  }
1945 
1946  return true;
1947 }
1948 
1949 
1950 /**
1951  * Copy the pixels within the indicated display region from the framebuffer
1952  * into system memory, not texture memory. Returns true on success, false on
1953  * failure.
1954  *
1955  * This completely redefines the ram image of the indicated texture.
1956  */
1958 framebuffer_copy_to_ram(Texture *tex, int view, int z,
1959  const DisplayRegion *dr, const RenderBuffer &rb) {
1960  return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, false);
1961 }
1962 
1963 /**
1964  * This is the implementation of framebuffer_copy_to_ram(); it adds one
1965  * additional parameter, which should be true if the framebuffer is to be
1966  * inverted during the copy (as in the same way it copies to texture memory).
1967  */
1969 do_framebuffer_copy_to_ram(Texture *tex, int view, int z,
1970  const DisplayRegion *dr, const RenderBuffer &rb,
1971  bool inverted) {
1972  set_read_buffer(rb);
1973 
1974  RECT rect;
1975  nassertr(tex != nullptr && dr != nullptr, false);
1976 
1977  int xo, yo, w, h;
1978  dr->get_region_pixels_i(xo, yo, w, h);
1979 
1980  Texture::Format format = tex->get_format();
1981  Texture::ComponentType component_type = tex->get_component_type();
1982 
1983  switch (format) {
1984  case Texture::F_depth_stencil:
1985  // Sorry, not (yet?) supported in pandadx.
1986  return false;
1987 
1988  default:
1989  format = Texture::F_rgb;
1990  component_type = Texture::T_unsigned_byte;
1991  }
1992 
1993  Texture::TextureType texture_type;
1994  if (z >= 0) {
1995  texture_type = Texture::TT_cube_map;
1996  } else {
1997  texture_type = Texture::TT_2d_texture;
1998  }
1999 
2000  if (tex->get_x_size() != w || tex->get_y_size() != h ||
2001  tex->get_component_type() != component_type ||
2002  tex->get_format() != format ||
2003  tex->get_texture_type() != texture_type) {
2004  // Re-setup the texture; its properties have changed.
2005  tex->setup_texture(texture_type, w, h, tex->get_z_size(),
2006  component_type, format);
2007  }
2008 
2009  rect.top = yo;
2010  rect.left = xo;
2011  rect.right = xo + w;
2012  rect.bottom = yo + h;
2013  bool copy_inverted = false;
2014 
2015  IDirect3DSurface9 *temp_surface = nullptr;
2016  HRESULT hr;
2017 
2018  // Note if you try to grab the backbuffer and full-screen anti-aliasing is
2019  // on, the backbuffer might be larger than the window size. For screenshots
2020  // it's safer to get the front buffer.
2021  if (_cur_read_pixel_buffer & RenderBuffer::T_back) {
2022  DWORD render_target_index;
2023  IDirect3DSurface9 *backbuffer = nullptr;
2024  // GetRenderTarget() seems to be a little more reliable than
2025  // GetBackBuffer(). Might just be related to the swap_chain thing.
2026 
2027  render_target_index = 0;
2028  hr = _d3d_device->GetRenderTarget(render_target_index, &backbuffer);
2029 
2030  if (FAILED(hr)) {
2031  dxgsg9_cat.error() << "GetRenderTarget failed" << D3DERRORSTRING(hr);
2032  return false;
2033  }
2034 
2035  // Since we might not be able to Lock the back buffer, we will need to
2036  // copy it to a temporary surface of the appropriate type first.
2037  D3DPOOL pool;
2038  D3DSURFACE_DESC surface_description;
2039 
2040  backbuffer -> GetDesc (&surface_description);
2041 
2042  pool = D3DPOOL_SYSTEMMEM;
2043  hr = _d3d_device->CreateOffscreenPlainSurface(
2044  surface_description.Width,
2045  surface_description.Height,
2046  surface_description.Format,
2047  pool,
2048  &temp_surface,
2049  nullptr);
2050  if (FAILED(hr)) {
2051  dxgsg9_cat.error()
2052  << "CreateImageSurface failed in copy_pixel_buffer()"
2053  << D3DERRORSTRING(hr);
2054  backbuffer->Release();
2055  return false;
2056  }
2057 
2058  // Now we must copy from the backbuffer to our temporary surface.
2059  hr = _d3d_device -> GetRenderTargetData (backbuffer, temp_surface);
2060  if (FAILED(hr)) {
2061  dxgsg9_cat.error() << "GetRenderTargetData failed" << D3DERRORSTRING(hr);
2062  temp_surface->Release();
2063  backbuffer->Release();
2064  return false;
2065  }
2066 
2067  copy_inverted = true;
2068 
2069  RELEASE(backbuffer, dxgsg9, "backbuffer", RELEASE_ONCE);
2070 
2071  } else if (_cur_read_pixel_buffer & RenderBuffer::T_front) {
2072 
2073  if (_screen->_presentation_params.Windowed) {
2074  // GetFrontBuffer() retrieves the entire desktop for a monitor, so we
2075  // need to reserve space for that.
2076 
2077  // We have to use GetMonitorInfo(), since this GSG may not be for the
2078  // primary monitor.
2079  MONITORINFO minfo;
2080  minfo.cbSize = sizeof(MONITORINFO);
2081  GetMonitorInfo(_screen->_monitor, &minfo);
2082 
2083  w = RECT_XSIZE(minfo.rcMonitor);
2084  h = RECT_YSIZE(minfo.rcMonitor);
2085 
2086  // set rect to client area of window in scrn coords
2087  ClientToScreen(_screen->_window, (POINT*)&rect.left);
2088  ClientToScreen(_screen->_window, (POINT*)&rect.right);
2089  }
2090 
2091  // For GetFrontBuffer(), we need a temporary surface of type A8R8G8B8.
2092  // Unlike GetBackBuffer(), GetFrontBuffer() implicitly performs a copy.
2093  hr = _d3d_device->CreateOffscreenPlainSurface(w, h, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &temp_surface, nullptr);
2094  if (FAILED(hr)) {
2095  dxgsg9_cat.error()
2096  << "CreateImageSurface failed in copy_pixel_buffer()"
2097  << D3DERRORSTRING(hr);
2098  return false;
2099  }
2100 
2101  UINT swap_chain;
2102 
2103  swap_chain = 0;
2104  hr = _d3d_device->GetFrontBufferData(swap_chain,temp_surface);
2105 
2106  if (hr == D3DERR_DEVICELOST) {
2107  dxgsg9_cat.error()
2108  << "copy_pixel_buffer failed: device lost\n";
2109  temp_surface->Release();
2110  return false;
2111  }
2112 
2113  copy_inverted = true;
2114 
2115  } else {
2116  dxgsg9_cat.error()
2117  << "copy_pixel_buffer: unhandled current_read_pixel_buffer type\n";
2118  temp_surface->Release();
2119  return false;
2120  }
2121 
2122  if (inverted) {
2123  copy_inverted = !copy_inverted;
2124  }
2125  DXTextureContext9::d3d_surface_to_texture(rect, temp_surface,
2126  copy_inverted, tex, view, z);
2127 
2128  RELEASE(temp_surface, dxgsg9, "temp_surface", RELEASE_ONCE);
2129 
2130  nassertr(tex->has_ram_image(), false);
2131  return true;
2132 }
2133 
2134 void DXGraphicsStateGuardian9::reset_render_states (void)
2135 {
2136  int index;
2137  int maximum_texture_stages;
2138 
2139  maximum_texture_stages = D3D_MAXTEXTURESTAGES;
2140 
2141  // set to invalid values so that the state will always be set the first time
2142  memset (_render_state_array, -1, sizeof (_render_state_array));
2143  memset (_texture_stage_states_array, -1, sizeof (_texture_stage_states_array));
2144 
2145  // states that may be set intially to -1 by the user, so set it to D3D's
2146  // default value
2147  _render_state_array [D3DRS_FOGCOLOR] = 0;
2148  _render_state_array [D3DRS_AMBIENT] = 0;
2149 
2150  // set to D3D default values or invalid values so that the state will always
2151  // be set the first time
2152  memset (_texture_render_states_array, 0, sizeof (_texture_render_states_array));
2153 
2154  // states that may be set intially to 0 by the user, so set it to D3D's
2155  // default value
2156  for (index = 0; index < MAXIMUM_TEXTURES; index++) {
2157  TextureRenderStates *texture_render_states;
2158 
2159  texture_render_states = &_texture_render_states_array [index];
2160  texture_render_states -> state_array [D3DSAMP_MAGFILTER] = D3DTEXF_POINT;
2161  texture_render_states -> state_array [D3DSAMP_MINFILTER] = D3DTEXF_POINT;
2162  texture_render_states -> state_array [D3DSAMP_MAXANISOTROPY] = 1;
2163  }
2164  _num_active_texture_stages = 0;
2165 
2166  set_render_state(D3DRS_NORMALIZENORMALS, false);
2167 
2168  _last_fvf = 0;
2169 }
2170 
2171 /**
2172  * Resets all internal state as if the gsg were newly created. The
2173  * GraphicsWindow pointer represents a typical window that might be used for
2174  * this context; it may be required to set up the frame buffer properly the
2175  * first time.
2176  */
2180 
2181  // Build _inv_state_mask as a mask of 1's where we don't care, and 0's where
2182  // we do care, about the state.
2183  _inv_state_mask.clear_bit(ShaderAttrib::get_class_slot());
2184  _inv_state_mask.clear_bit(AlphaTestAttrib::get_class_slot());
2185  _inv_state_mask.clear_bit(ClipPlaneAttrib::get_class_slot());
2186  _inv_state_mask.clear_bit(ColorAttrib::get_class_slot());
2187  _inv_state_mask.clear_bit(ColorScaleAttrib::get_class_slot());
2188  _inv_state_mask.clear_bit(CullFaceAttrib::get_class_slot());
2189  _inv_state_mask.clear_bit(DepthOffsetAttrib::get_class_slot());
2190  _inv_state_mask.clear_bit(DepthTestAttrib::get_class_slot());
2191  _inv_state_mask.clear_bit(DepthWriteAttrib::get_class_slot());
2192  _inv_state_mask.clear_bit(RenderModeAttrib::get_class_slot());
2193  _inv_state_mask.clear_bit(RescaleNormalAttrib::get_class_slot());
2194  _inv_state_mask.clear_bit(ShadeModelAttrib::get_class_slot());
2195  _inv_state_mask.clear_bit(TransparencyAttrib::get_class_slot());
2196  _inv_state_mask.clear_bit(ColorWriteAttrib::get_class_slot());
2197  _inv_state_mask.clear_bit(ColorBlendAttrib::get_class_slot());
2198  _inv_state_mask.clear_bit(TextureAttrib::get_class_slot());
2199  _inv_state_mask.clear_bit(TexGenAttrib::get_class_slot());
2200  _inv_state_mask.clear_bit(TexMatrixAttrib::get_class_slot());
2201  _inv_state_mask.clear_bit(MaterialAttrib::get_class_slot());
2202  _inv_state_mask.clear_bit(LightAttrib::get_class_slot());
2203  _inv_state_mask.clear_bit(StencilAttrib::get_class_slot());
2204  _inv_state_mask.clear_bit(FogAttrib::get_class_slot());
2205  _inv_state_mask.clear_bit(ScissorAttrib::get_class_slot());
2206 
2207  // D3DRS_POINTSPRITEENABLE doesn't seem to support remapping the texture
2208  // coordinates via a texture matrix, so we don't advertise
2209  // GR_point_sprite_tex_matrix.
2210  _supported_geom_rendering =
2211  Geom::GR_point | Geom::GR_point_uniform_size |
2212  Geom::GR_point_perspective | Geom::GR_point_sprite |
2213  Geom::GR_indexed_other |
2214  Geom::GR_triangle_strip | Geom::GR_triangle_fan |
2215  Geom::GR_flat_first_vertex |
2216  Geom::GR_render_mode_wireframe | Geom::GR_render_mode_point;
2217 
2218  // overwrite gsg defaults with these values
2219 
2220  HRESULT hr;
2221 
2222  // make sure gsg passes all current state down to us
2223  // set_state_and_transform(RenderState::make_empty(),
2224  // TransformState::make_identity()); want gsg to pass all state settings
2225  // down so any non-matching defaults we set here get overwritten
2226 
2227  nassertv(_screen->_d3d9 != nullptr);
2228 
2229  if (_d3d_device == nullptr) {
2230  return;
2231  }
2232 
2233  D3DCAPS9 d3d_caps;
2234  _d3d_device->GetDeviceCaps(&d3d_caps);
2235 
2236  _vertex_shader_version_major = D3DSHADER_VERSION_MAJOR (d3d_caps.VertexShaderVersion);
2237  _vertex_shader_version_minor = D3DSHADER_VERSION_MINOR (d3d_caps.VertexShaderVersion);
2238  _pixel_shader_version_major = D3DSHADER_VERSION_MAJOR (d3d_caps.PixelShaderVersion);
2239  _pixel_shader_version_minor = D3DSHADER_VERSION_MINOR (d3d_caps.PixelShaderVersion);
2240 
2241  _supports_hlsl = (_pixel_shader_version_major != 0);
2242 
2243  _vertex_shader_profile = (char *) D3DXGetVertexShaderProfile (_d3d_device);
2244  _pixel_shader_profile = (char *) D3DXGetPixelShaderProfile (_d3d_device);
2245 
2246  _vertex_shader_maximum_constants = d3d_caps.MaxVertexShaderConst;
2247 
2248  switch (_pixel_shader_version_major)
2249  {
2250  case 0:
2251  _shader_model = SM_00;
2252  break;
2253  case 1:
2254  _shader_model = SM_11;
2255  break;
2256  case 2:
2257  // minimim specification for pixel shader 2.0 is 96 instruction slots
2258  _shader_model = SM_20;
2259  if (d3d_caps.PS20Caps.NumInstructionSlots >= 512) {
2260  _shader_model = SM_2X;
2261  }
2262  break;
2263  case 3:
2264  _shader_model = SM_30;
2265  break;
2266  case 4:
2267  _shader_model = SM_40;
2268  break;
2269  case 5:
2270  default:
2271  _shader_model = SM_50;
2272  break;
2273  }
2274 
2275  _auto_detect_shader_model = _shader_model;
2276 
2277 #ifdef HAVE_CG
2278  set_cg_device(_d3d_device);
2279 
2280  _cg_context = cgCreateContext();
2281 
2282  if (cgD3D9IsProfileSupported(CG_PROFILE_PS_2_0) &&
2283  cgD3D9IsProfileSupported(CG_PROFILE_VS_2_0)) {
2284  _supports_basic_shaders = true;
2285  _shader_caps._active_vprofile = (int)cgD3D9GetLatestVertexProfile();
2286  _shader_caps._active_fprofile = (int)cgD3D9GetLatestPixelProfile();
2287  _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VS_3_0;
2288  _shader_caps._ultimate_fprofile = (int)CG_PROFILE_PS_3_0;
2289 /*
2290  _shader_caps._active_vprofile = (int)CG_PROFILE_VS_2_0;
2291  _shader_caps._active_fprofile = (int)CG_PROFILE_PS_2_0;
2292  _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VS_2_0;
2293  _shader_caps._ultimate_fprofile = (int)CG_PROFILE_PS_2_0;
2294 */
2295  }
2296 
2297  if (dxgsg9_cat.is_debug()) {
2298  CGprofile vertex_profile;
2299  CGprofile pixel_profile;
2300 
2301  vertex_profile = cgD3D9GetLatestVertexProfile();
2302  pixel_profile = cgD3D9GetLatestPixelProfile();
2303 
2304  const char *vertex_profile_str =
2305  cgGetProfileString(vertex_profile);
2306  const char *pixel_profile_str =
2307  cgGetProfileString(pixel_profile);
2308 
2309  if (vertex_profile_str == nullptr) {
2310  vertex_profile_str = "(null)";
2311  }
2312  if (pixel_profile_str == nullptr) {
2313  pixel_profile_str = "(null)";
2314  }
2315 
2316  dxgsg9_cat.debug()
2317  << "\nCg latest vertex profile = " << vertex_profile_str << " id = " << vertex_profile
2318  << "\nCg latest pixel profile = " << pixel_profile_str << " id = " << pixel_profile
2319  << "\nshader model = " << _shader_model
2320  << "\n";
2321  }
2322 #endif
2323 
2324  _supports_stream_offset = (d3d_caps.DevCaps2 & D3DDEVCAPS2_STREAMOFFSET) != 0;
2325  _screen->_supports_dynamic_textures = ((d3d_caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) != 0);
2326  _screen->_supports_automatic_mipmap_generation = ((d3d_caps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP) != 0);
2327 
2328  if (support_stencil) {
2329  int min_stencil = D3DSTENCILCAPS_ZERO | D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_INCR | D3DSTENCILCAPS_DECR;
2330  if ((d3d_caps.StencilCaps & min_stencil) == min_stencil) {
2331  if (dxgsg9_cat.is_debug()) {
2332  dxgsg9_cat.debug()
2333  << "Checking for stencil; mode = "
2334  << D3DFormatStr(_screen->_presentation_params.AutoDepthStencilFormat)
2335  << "\n";
2336  }
2337  switch (_screen->_presentation_params.AutoDepthStencilFormat) {
2338  // These are the only formats that support stencil.
2339  case D3DFMT_D15S1:
2340  case D3DFMT_D24S8:
2341  case D3DFMT_D24X4S4:
2342  _supports_stencil = true;
2343  if (dxgsg9_cat.is_debug()) {
2344  dxgsg9_cat.debug()
2345  << "Stencils supported.\n";
2346  }
2347  break;
2348 
2349  default:
2350  if (dxgsg9_cat.is_debug()) {
2351  dxgsg9_cat.debug()
2352  << "Stencils NOT supported.\n";
2353  }
2354  }
2355  }
2356  }
2357 
2358  _supports_stencil_wrap = (d3d_caps.StencilCaps & D3DSTENCILCAPS_INCR) && (d3d_caps.StencilCaps & D3DSTENCILCAPS_DECR);
2359  _supports_two_sided_stencil = ((d3d_caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) != 0);
2360 
2361  _max_color_targets = d3d_caps.NumSimultaneousRTs;
2362 
2363  _supports_depth_bias = ((d3d_caps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS)) == (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS));
2364 
2365  _supports_gamma_calibration = ((d3d_caps.Caps2 & D3DCAPS2_CANCALIBRATEGAMMA) != 0);
2366 
2367  // Test for occlusion query support
2368  hr = _d3d_device->CreateQuery(D3DQUERYTYPE_OCCLUSION, nullptr);
2369  _supports_occlusion_query = !FAILED(hr);
2370 
2371  if (dxgsg9_cat.is_error()) {
2372  dxgsg9_cat.debug()
2373  << "\nHwTransformAndLight = " << ((d3d_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0)
2374  << "\nMaxTextureWidth = " << d3d_caps.MaxTextureWidth
2375  << "\nMaxTextureHeight = " << d3d_caps.MaxTextureHeight
2376  << "\nMaxVolumeExtent = " << d3d_caps.MaxVolumeExtent
2377  << "\nMaxTextureAspectRatio = " << d3d_caps.MaxTextureAspectRatio
2378  << "\nTexCoordCount = " << (d3d_caps.FVFCaps & D3DFVFCAPS_TEXCOORDCOUNTMASK)
2379  << "\nMaxTextureBlendStages = " << d3d_caps.MaxTextureBlendStages
2380  << "\nMaxSimultaneousTextures = " << d3d_caps.MaxSimultaneousTextures
2381  << "\nMaxActiveLights = " << d3d_caps.MaxActiveLights
2382  << "\nMaxUserClipPlanes = " << d3d_caps.MaxUserClipPlanes
2383  << "\nMaxVertexBlendMatrices = " << d3d_caps.MaxVertexBlendMatrices
2384  << "\nMaxVertexBlendMatrixIndex = " << d3d_caps.MaxVertexBlendMatrixIndex
2385  << "\nMaxPointSize = " << d3d_caps.MaxPointSize
2386  << "\nMaxPrimitiveCount = " << d3d_caps.MaxPrimitiveCount
2387  << "\nMaxVertexIndex = " << d3d_caps.MaxVertexIndex
2388  << "\nMaxStreams = " << d3d_caps.MaxStreams
2389  << "\nMaxStreamStride = " << d3d_caps.MaxStreamStride
2390  << "\nD3DTEXOPCAPS_MULTIPLYADD = " << ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_MULTIPLYADD) != 0)
2391  << "\nD3DTEXOPCAPS_LERP = " << ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_LERP) != 0)
2392  << "\nD3DPMISCCAPS_TSSARGTEMP = " << ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) != 0)
2393  << "\nD3DPRASTERCAPS_DEPTHBIAS = " << ((d3d_caps.RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0)
2394  << "\nD3DPRASTERCAPS_SLOPESCALEDEPTHBIAS = " << ((d3d_caps.RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS) != 0)
2395  << "\nVertexShaderVersion = " << _vertex_shader_version_major << "." << _vertex_shader_version_minor
2396  << "\nPixelShaderVersion = " << _pixel_shader_version_major << "." << _pixel_shader_version_minor
2397  << "\nMaxVertexShaderConst = " << _vertex_shader_maximum_constants
2398  << "\nsupports_stream_offset = " << _supports_stream_offset
2399  << "\nsupports_dynamic_textures = " << _screen->_supports_dynamic_textures
2400  << "\nsupports_automatic_mipmap_generation = " << _screen->_supports_automatic_mipmap_generation
2401  << "\nsupports_stencil_wrap = " << _supports_stencil_wrap
2402  << "\nsupports_two_sided_stencil = " << _supports_two_sided_stencil
2403  << "\nsupports_occlusion_query = " << _supports_occlusion_query
2404  << "\nsupports_gamma_calibration = " << _supports_gamma_calibration
2405  << "\nMaxAnisotropy = " << d3d_caps.MaxAnisotropy
2406  << "\nNumSimultaneousRTs = " << d3d_caps.NumSimultaneousRTs
2407  << "\nD3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING = " << ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING) != 0)
2408  << "\nDirectX SDK version " DIRECTX_SDK_VERSION
2409  << "\n";
2410  }
2411 
2412  // OVERRIDE SUPPORT SINCE IT DOES NOT WORK WELL
2413  _screen->_supports_automatic_mipmap_generation = false;
2414 
2415  reset_render_states();
2416 
2417  _max_vertices_per_array = d3d_caps.MaxVertexIndex;
2418  _max_vertices_per_primitive = d3d_caps.MaxPrimitiveCount;
2419 
2420  _max_texture_stages = d3d_caps.MaxSimultaneousTextures;
2421 
2422  _max_texture_dimension = min(d3d_caps.MaxTextureWidth, d3d_caps.MaxTextureHeight);
2423 
2424  _supports_tex_non_pow2 = !(d3d_caps.TextureCaps & D3DPTEXTURECAPS_POW2);
2425 
2426  _supports_texture_combine = ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_LERP) != 0);
2427  _supports_texture_saved_result = ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) != 0);
2428  _supports_texture_constant_color = ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_PERSTAGECONSTANT) != 0);
2429  _supports_texture_dot3 = true;
2430 
2431  if (_supports_texture_constant_color) {
2432  _constant_color_operand = D3DTA_CONSTANT;
2433  } else {
2434  _constant_color_operand = D3DTA_TFACTOR;
2435  }
2436 
2437  _screen->_managed_textures = _gsg_managed_textures;
2438  _screen->_managed_vertex_buffers = _gsg_managed_vertex_buffers;
2439  _screen->_managed_index_buffers = _gsg_managed_index_buffers;
2440 
2441  UINT available_texture_memory;
2442 
2443  available_texture_memory = _d3d_device->GetAvailableTextureMem ( );
2444  if (dxgsg9_cat.is_debug()) {
2445  dxgsg9_cat.debug() << "*** GetAvailableTextureMem = " << available_texture_memory << "\n";
2446  }
2447  _available_texture_memory = available_texture_memory;
2448 
2449  // check for render to texture support
2450  D3DDEVICE_CREATION_PARAMETERS creation_parameters;
2451 
2452  _supports_render_texture = false;
2453  _screen->_render_to_texture_d3d_format = D3DFMT_UNKNOWN;
2454  _screen->_framebuffer_d3d_format = D3DFMT_UNKNOWN;
2455 
2456  #define TOTAL_RENDER_TO_TEXTURE_FORMATS 3
2457 
2458  D3DFORMAT render_to_texture_formats [TOTAL_RENDER_TO_TEXTURE_FORMATS] =
2459  {
2460  D3DFMT_A8R8G8B8, // check for this format first
2461  D3DFMT_X8R8G8B8,
2462  D3DFMT_UNKNOWN, // place holder for _screen->_display_mode.Format
2463  };
2464 
2465  render_to_texture_formats [TOTAL_RENDER_TO_TEXTURE_FORMATS - 1] = _screen->_display_mode.Format;
2466 
2467  hr = _d3d_device->GetCreationParameters (&creation_parameters);
2468  if (SUCCEEDED (hr)) {
2469  _screen->_framebuffer_d3d_format = _screen->_display_mode.Format;
2470 
2471  int index;
2472  for (index = 0; index < TOTAL_RENDER_TO_TEXTURE_FORMATS; index++) {
2473  hr = _screen->_d3d9->CheckDeviceFormat (
2474  creation_parameters.AdapterOrdinal,
2475  creation_parameters.DeviceType,
2476  _screen->_display_mode.Format,
2477  D3DUSAGE_RENDERTARGET,
2478  D3DRTYPE_TEXTURE,
2479  render_to_texture_formats [index]);
2480  if (SUCCEEDED (hr)) {
2481  _screen->_render_to_texture_d3d_format = render_to_texture_formats [index];
2482  _supports_render_texture = true;
2483  }
2484  if (_supports_render_texture) {
2485  break;
2486  }
2487  }
2488  }
2489  if (dxgsg9_cat.is_debug()) {
2490  dxgsg9_cat.debug() << "Render to Texture Support = " << _supports_render_texture << "\n";
2491  }
2492 
2493  // override default config setting since it is really supported or not ???
2494  // support_render_texture = _supports_render_texture;
2495 
2496  _supports_3d_texture = ((d3d_caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) != 0);
2497  if (_supports_3d_texture) {
2498  _max_3d_texture_dimension = d3d_caps.MaxVolumeExtent;
2499  }
2500  _supports_cube_map = ((d3d_caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) != 0);
2501  if (_supports_cube_map) {
2502  _max_cube_map_dimension = _max_texture_dimension;
2503  }
2504 
2505  _max_lights = (int)d3d_caps.MaxActiveLights;
2506  _max_clip_planes = (int)d3d_caps.MaxUserClipPlanes;
2507  _max_vertex_transforms = d3d_caps.MaxVertexBlendMatrices;
2508  _max_vertex_transform_indices = d3d_caps.MaxVertexBlendMatrixIndex;
2509 
2510  set_render_state(D3DRS_AMBIENT, 0x0);
2511 
2512  _clip_plane_bits = 0;
2513  set_render_state(D3DRS_CLIPPLANEENABLE , 0x0);
2514 
2515  set_render_state(D3DRS_CLIPPING, true);
2516 
2517  set_render_state(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
2518 
2519  set_render_state(D3DRS_ZWRITEENABLE, TRUE);
2520 
2521 /* ***** DX9 ??? D3DRS_EDGEANTIALIAS NOT IN DX9 */
2522 // set_render_state(D3DRS_EDGEANTIALIAS, false);
2523 
2524  set_render_state(D3DRS_ZENABLE, D3DZB_FALSE);
2525 
2526  set_render_state(D3DRS_ALPHABLENDENABLE, FALSE);
2527 
2528  set_render_state(D3DRS_FOGENABLE, FALSE);
2529 
2530  _has_scene_graph_color = false;
2531 
2532  _last_testcooplevel_result = D3D_OK;
2533 
2534  if (dxgsg9_cat.is_debug()) {
2535  dxgsg9_cat.debug() << "Supported texture formats:\n";
2536  }
2537 
2538  for(int i = 0; i < MAX_POSSIBLE_TEXFMTS; i++) {
2539  // look for all possible DX9 texture fmts
2540  D3DFORMAT_FLAG fmtflag = D3DFORMAT_FLAG(1 << i);
2541  hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format,
2542  0x0, D3DRTYPE_TEXTURE, g_D3DFORMATmap[fmtflag]);
2543  if (SUCCEEDED(hr)) {
2544  if (dxgsg9_cat.is_debug()) {
2545  dxgsg9_cat.debug() << " " << D3DFormatStr(g_D3DFORMATmap[fmtflag]) << "\n";
2546  }
2547  _screen->_supported_tex_formats_mask |= fmtflag;
2548  }
2549  }
2550 
2551  _supports_depth_stencil = ((_screen->_supported_tex_formats_mask & D24S8_FLAG) != 0);
2552  _supports_depth_texture = _supports_depth_stencil ||
2553  (_screen->_supported_tex_formats_mask & D16_FLAG) != 0 ||
2554  (_screen->_supported_tex_formats_mask & D32_FLAG) != 0 ||
2555  (_screen->_supported_tex_formats_mask & D24X8_FLAG) != 0;
2556 
2557  // In DirectX 9, all built-in depth formats use shadow map filtering. Some
2558  // drivers (GeForce 8000+, Radeon HD 4000+, Intel G45+) expose a FourCC
2559  // format called "INTZ" that allows access to the actual depth. We don't
2560  // have a flag to indicate this, though.
2561  _supports_shadow_filter = _supports_depth_texture;
2562 
2563  // check if compressed textures are supported
2564  #define CHECK_COMPRESSED_FMT(mode, fmt) \
2565  if (_screen->_supported_tex_formats_mask & fmt##_FLAG) {\
2566  if (dxgsg9_cat.is_debug()) {\
2567  dxgsg9_cat.debug() << "Compressed texture format " << #fmt << " supported\n";\
2568  }\
2569  _supports_compressed_texture = true;\
2570  _compressed_texture_formats.set_bit(Texture::mode);\
2571  }
2572 
2573  if (_screen->_intel_compressed_texture_bug) {
2574  dxgsg9_cat.info()
2575  << "Buggy Intel driver detected; disabling compressed textures.\n";
2576  _screen->_supported_tex_formats_mask &=
2577  ~(DXT1_FLAG | DXT2_FLAG | DXT3_FLAG | DXT4_FLAG | DXT5_FLAG);
2578 
2579  } else {
2580  // Check for available compressed formats normally.
2581  CHECK_COMPRESSED_FMT(CM_dxt1, DXT1);
2582  CHECK_COMPRESSED_FMT(CM_dxt2, DXT2);
2583  CHECK_COMPRESSED_FMT(CM_dxt3, DXT3);
2584  CHECK_COMPRESSED_FMT(CM_dxt4, DXT4);
2585  CHECK_COMPRESSED_FMT(CM_dxt5, DXT5);
2586  CHECK_COMPRESSED_FMT(CM_rgtc, ATI1);
2587  CHECK_COMPRESSED_FMT(CM_rgtc, ATI2);
2588  }
2589 
2590  #undef CHECK_COMPRESSED_FMT
2591 
2592  _screen->_supports_rgba16f_texture_format = false;
2593  hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format, 0x0, D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F);
2594  if (SUCCEEDED(hr)){
2595  _screen->_supports_rgba16f_texture_format = true;
2596  }
2597  _screen->_supports_rgba32_texture_format = false;
2598  hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format, 0x0, D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F);
2599  if (SUCCEEDED(hr)){
2600  _screen->_supports_rgba32_texture_format = true;
2601  }
2602 
2603  // s3 virge drivers sometimes give crap values for these
2604  if (_screen->_d3dcaps.MaxTextureWidth == 0)
2605  _screen->_d3dcaps.MaxTextureWidth = 256;
2606 
2607  if (_screen->_d3dcaps.MaxTextureHeight == 0)
2608  _screen->_d3dcaps.MaxTextureHeight = 256;
2609 
2610  if (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGTABLE) {
2611  // Watch out for drivers that emulate per-pixel fog with per-vertex fog
2612  // (Riva128, Matrox Millen G200). Some of these require gouraud-shading
2613  // to be set to work, as if you were using vertex fog
2614  _do_fog_type = PerPixelFog;
2615  } else {
2616  // every card is going to have vertex fog, since it's implemented in d3d
2617  // runtime.
2618  nassertv((_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGVERTEX) != 0);
2619 
2620  // vertex fog may look crappy if you have large polygons in the foreground
2621  // and they get clipped, so you may want to disable it
2622 
2623  if (dx_no_vertex_fog) {
2624  _do_fog_type = None;
2625  } else {
2626  _do_fog_type = PerVertexFog;
2627 
2628  // range-based fog only works with vertex fog in dx78
2629  if (dx_use_rangebased_fog && (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGRANGE)) {
2630  set_render_state(D3DRS_RANGEFOGENABLE, true);
2631  }
2632  }
2633  }
2634 
2635  _screen->_can_direct_disable_color_writes = ((_screen->_d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) != 0);
2636 
2637  // Lighting, let's turn it off initially.
2638  set_render_state(D3DRS_LIGHTING, false);
2639 
2640  // turn on dithering if the rendertarget is < 8bitscolor channel
2641  bool dither_enabled = ((!dx_no_dithering) && IS_16BPP_DISPLAY_FORMAT(_screen->_presentation_params.BackBufferFormat)
2642  && (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_DITHER));
2643  set_render_state(D3DRS_DITHERENABLE, dither_enabled);
2644 
2645  set_render_state(D3DRS_CLIPPING, true);
2646 
2647  // Stencil test is off by default
2648  set_render_state(D3DRS_STENCILENABLE, FALSE);
2649  if (_supports_two_sided_stencil) {
2650  set_render_state(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
2651  }
2652 
2653  // Antialiasing.
2654 /* ***** DX9 ??? D3DRS_EDGEANTIALIAS NOT IN DX9 */
2655 // set_render_state(D3DRS_EDGEANTIALIAS, FALSE);
2656 
2657  _current_fill_mode = RenderModeAttrib::M_filled;
2658  set_render_state(D3DRS_FILLMODE, D3DFILL_SOLID);
2659 
2660  // must do SetTSS here because redundant states are filtered out by our code
2661  // based on current values above, so initial conditions must be correct
2662  set_texture_stage_state(0, D3DTSS_COLOROP, D3DTOP_DISABLE); // disables texturing
2663 
2664  _cull_face_mode = CullFaceAttrib::M_cull_none;
2665  set_render_state(D3DRS_CULLMODE, D3DCULL_NONE);
2666 
2667  set_render_state(D3DRS_ALPHAFUNC, D3DCMP_ALWAYS);
2668  set_render_state(D3DRS_ALPHAREF, 255);
2669  set_render_state(D3DRS_ALPHATESTENABLE, FALSE);
2670 
2671  // this is a new DX8 state that lets you do additional operations other than
2672  // ADD (e.g. subtractmaxmin) must check
2673  // (_screen->_d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) (yes on
2674  // GF2Radeon8500, no on TNT)
2675  set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
2676 
2677  _current_shader = nullptr;
2678  _current_shader_context = nullptr;
2679  _vertex_array_shader = nullptr;
2680  _vertex_array_shader_context = nullptr;
2681  _texture_binding_shader = nullptr;
2682  _texture_binding_shader_context = nullptr;
2683 
2684  PRINT_REFCNT(dxgsg9, _d3d_device);
2685 
2686  // Now that the GSG has been initialized, make it available for
2687  // optimizations.
2688  add_gsg(this);
2689 }
2690 
2691 /**
2692  *
2693  */
2694 void DXGraphicsStateGuardian9::
2695 apply_fog(Fog *fog) {
2696  if (_do_fog_type == None)
2697  return;
2698 
2699  Fog::Mode panda_fogmode = fog->get_mode();
2700  D3DFOGMODE d3dfogmode = get_fog_mode_type(panda_fogmode);
2701 
2702  set_render_state((D3DRENDERSTATETYPE)_do_fog_type, d3dfogmode);
2703 
2704  const LColor &fog_colr = fog->get_color();
2705  set_render_state(D3DRS_FOGCOLOR,
2706  MY_D3DRGBA(fog_colr[0], fog_colr[1], fog_colr[2], 0.0f)); // Alpha bits are not used
2707 
2708  // do we need to adjust fog startend values based on
2709  // D3DPRASTERCAPS_WFOGD3DPRASTERCAPS_ZFOG ? if not WFOG, then docs say we
2710  // need to adjust values to range [0, 1]
2711 
2712  switch (panda_fogmode) {
2713  case Fog::M_linear:
2714  {
2715  PN_stdfloat onset, opaque;
2716  fog->get_linear_range(onset, opaque);
2717 
2718  set_render_state(D3DRS_FOGSTART,
2719  *((LPDWORD) (&onset)));
2720  set_render_state(D3DRS_FOGEND,
2721  *((LPDWORD) (&opaque)));
2722  }
2723  break;
2724  case Fog::M_exponential:
2725  case Fog::M_exponential_squared:
2726  {
2727  // Exponential fog is always camera-relative.
2728  PN_stdfloat fog_density = fog->get_exp_density();
2729  set_render_state(D3DRS_FOGDENSITY,
2730  *((LPDWORD) (&fog_density)));
2731  }
2732  break;
2733  }
2734 }
2735 
2736 /**
2737  * Sends the indicated transform matrix to the graphics API to be applied to
2738  * future vertices.
2739  *
2740  * This transform is the internal_transform, already converted into the GSG's
2741  * internal coordinate system.
2742  */
2743 void DXGraphicsStateGuardian9::
2744 do_issue_transform() {
2745  const TransformState *transform = _internal_transform;
2746  DO_PSTATS_STUFF(_transform_state_pcollector.add_level(1));
2747 
2748  if (_current_shader_context) {
2749 // _current_shader_context->issue_transform(this);
2750  _current_shader_context->issue_parameters(this, Shader::SSD_transform);
2751 
2752 // ??? NO NEED TO SET THE D3D TRANSFORM VIA SetTransform SINCE THE TRANSFORM
2753 // IS ONLY USED IN THE SHADER
2754  LMatrix4f mat = LCAST(float, transform->get_mat());
2755  const D3DMATRIX *d3d_mat = (const D3DMATRIX *)mat.get_data();
2756  _d3d_device->SetTransform(D3DTS_WORLD, d3d_mat);
2757 
2758  }
2759  else {
2760  LMatrix4f mat = LCAST(float, transform->get_mat());
2761  const D3DMATRIX *d3d_mat = (const D3DMATRIX *)mat.get_data();
2762  _d3d_device->SetTransform(D3DTS_WORLD, d3d_mat);
2763 
2764 // DEBUG PRINT
2765 /*
2766  const PN_stdfloat *data;
2767  data = &d3d_mat -> _11;
2768  dxgsg9_cat.debug ( ) << "do_issue_transform\n" <<
2769  data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" <<
2770  data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" <<
2771  data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" <<
2772  data[12] << " " << data[13] << " " << data[14] << " " << data[15] << "\n";
2773 */
2774 
2775  }
2776 
2777  _transform_stale = false;
2778 }
2779 
2780 /**
2781  *
2782  */
2783 void DXGraphicsStateGuardian9::
2784 do_issue_alpha_test() {
2785  if (_target_shader->get_flag(ShaderAttrib::F_subsume_alpha_test)) {
2786  set_render_state(D3DRS_ALPHATESTENABLE, FALSE);
2787  } else {
2788  const AlphaTestAttrib *target_alpha_test = DCAST(AlphaTestAttrib, _target_rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
2789  AlphaTestAttrib::PandaCompareFunc mode = target_alpha_test->get_mode();
2790  if (mode == AlphaTestAttrib::M_none) {
2791  set_render_state(D3DRS_ALPHATESTENABLE, FALSE);
2792  } else {
2793  // AlphaTestAttrib::PandaCompareFunc === D3DCMPFUNC
2794  set_render_state(D3DRS_ALPHAFUNC, (D3DCMPFUNC)mode);
2795  set_render_state(D3DRS_ALPHAREF, (UINT) (target_alpha_test->get_reference_alpha()*255.0f)); //d3d uses 0x0-0xFF, not a float
2796  set_render_state(D3DRS_ALPHATESTENABLE, TRUE);
2797  }
2798  }
2799 }
2800 
2801 /**
2802  *
2803  */
2804 void DXGraphicsStateGuardian9::
2805 do_issue_shader() {
2806 
2807  DXShaderContext9 *context = 0;
2808  Shader *shader = 0;
2809  if (_target_shader) {
2810  shader = (Shader *)(_target_shader->get_shader());
2811  }
2812  if (shader) {
2813  context = (DXShaderContext9 *)(shader->prepare_now(get_prepared_objects(), this));
2814  }
2815 
2816  if (context == 0 || (context && context -> valid (this) == false)) {
2817  if (_current_shader_context != 0) {
2818  _current_shader_context->unbind(this);
2819  _current_shader = 0;
2820  _current_shader_context = 0;
2821  disable_standard_texture_bindings();
2822  }
2823  return;
2824  }
2825 
2826  if (context != _current_shader_context) {
2827  // Use a completely different shader than before. Unbind old shader, bind
2828  // the new one.
2829  if (_current_shader_context != 0) {
2830  _current_shader_context->unbind(this);
2831  _current_shader_context = 0;
2832  _current_shader = 0;
2833  disable_standard_texture_bindings();
2834  }
2835  if (context != 0) {
2836  context->bind(this);
2837  _current_shader = shader;
2838  _current_shader_context = context;
2839  }
2840  } else {
2841  // Use the same shader as before, but with new input arguments.
2842  context->issue_parameters(this, Shader::SSD_shaderinputs);
2843  }
2844 }
2845 
2846 /**
2847  *
2848  */
2849 void DXGraphicsStateGuardian9::
2850 do_issue_render_mode() {
2851  const RenderModeAttrib *target_render_mode;
2852  _target_rs->get_attrib_def(target_render_mode);
2853  RenderModeAttrib::Mode mode = target_render_mode->get_mode();
2854 
2855  switch (mode) {
2856  case RenderModeAttrib::M_unchanged:
2857  case RenderModeAttrib::M_filled:
2858  case RenderModeAttrib::M_filled_flat:
2859  set_render_state(D3DRS_FILLMODE, D3DFILL_SOLID);
2860  break;
2861 
2862  case RenderModeAttrib::M_wireframe:
2863  set_render_state(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
2864  break;
2865 
2866  case RenderModeAttrib::M_point:
2867  set_render_state(D3DRS_FILLMODE, D3DFILL_POINT);
2868  break;
2869 
2870  default:
2871  dxgsg9_cat.error()
2872  << "Unknown render mode " << (int)mode << endl;
2873  }
2874 
2875  // This might also specify the point size.
2876  PN_stdfloat point_size = target_render_mode->get_thickness();
2877  set_render_state(D3DRS_POINTSIZE, *((DWORD*)&point_size));
2878 
2879  if (target_render_mode->get_perspective()) {
2880  set_render_state(D3DRS_POINTSCALEENABLE, TRUE);
2881 
2882  LVector3 height(0.0f, point_size, 1.0f);
2883  height = height * _projection_mat->get_mat();
2884  PN_stdfloat s = height[1] / point_size;
2885 
2886  PN_stdfloat zero = 0.0f;
2887  PN_stdfloat one_over_s2 = 1.0f / (s * s);
2888  set_render_state(D3DRS_POINTSCALE_A, *((DWORD*)&zero));
2889  set_render_state(D3DRS_POINTSCALE_B, *((DWORD*)&zero));
2890  set_render_state(D3DRS_POINTSCALE_C, *((DWORD*)&one_over_s2));
2891 
2892  } else {
2893  set_render_state(D3DRS_POINTSCALEENABLE, FALSE);
2894  }
2895 
2896  _current_fill_mode = mode;
2897 }
2898 
2899 /**
2900  *
2901  */
2902 void DXGraphicsStateGuardian9::
2903 do_issue_rescale_normal() {
2904  RescaleNormalAttrib::Mode mode = RescaleNormalAttrib::M_none;
2905 
2906  const RescaleNormalAttrib *target_rescale_normal;
2907  if (_target_rs->get_attrib(target_rescale_normal)) {
2908  mode = target_rescale_normal->get_mode();
2909  }
2910 
2911  switch (mode) {
2912  case RescaleNormalAttrib::M_none:
2913  set_render_state(D3DRS_NORMALIZENORMALS, false);
2914  break;
2915 
2916  case RescaleNormalAttrib::M_rescale:
2917  case RescaleNormalAttrib::M_normalize:
2918  set_render_state(D3DRS_NORMALIZENORMALS, true);
2919  break;
2920 
2921  default:
2922  dxgsg9_cat.error()
2923  << "Unknown rescale_normal mode " << (int)mode << endl;
2924  }
2925 }
2926 
2927 /**
2928  *
2929  */
2930 void DXGraphicsStateGuardian9::
2931 do_issue_depth_test() {
2932  const DepthTestAttrib *target_depth_test = DCAST(DepthTestAttrib, _target_rs->get_attrib_def(DepthTestAttrib::get_class_slot()));
2933  DepthTestAttrib::PandaCompareFunc mode = target_depth_test->get_mode();
2934  if (mode == DepthTestAttrib::M_none) {
2935  set_render_state(D3DRS_ZENABLE, D3DZB_FALSE);
2936  } else {
2937  set_render_state(D3DRS_ZENABLE, D3DZB_TRUE);
2938  set_render_state(D3DRS_ZFUNC, (D3DCMPFUNC) mode);
2939  }
2940 }
2941 
2942 /**
2943  *
2944  */
2945 void DXGraphicsStateGuardian9::
2946 do_issue_depth_write() {
2947  const DepthWriteAttrib *target_depth_write = DCAST(DepthWriteAttrib, _target_rs->get_attrib_def(DepthWriteAttrib::get_class_slot()));
2948  DepthWriteAttrib::Mode mode = target_depth_write->get_mode();
2949  if (mode == DepthWriteAttrib::M_on) {
2950  set_render_state(D3DRS_ZWRITEENABLE, TRUE);
2951  } else {
2952  set_render_state(D3DRS_ZWRITEENABLE, FALSE);
2953  }
2954 }
2955 
2956 /**
2957  *
2958  */
2959 void DXGraphicsStateGuardian9::
2960 do_issue_cull_face() {
2961  const CullFaceAttrib *target_cull_face = DCAST(CullFaceAttrib, _target_rs->get_attrib_def(CullFaceAttrib::get_class_slot()));
2962  _cull_face_mode = target_cull_face->get_effective_mode();
2963 
2964  switch (_cull_face_mode) {
2965  case CullFaceAttrib::M_cull_none:
2966  set_render_state(D3DRS_CULLMODE, D3DCULL_NONE);
2967 
2968 // printf ("------------------- D3DCULL_NONE\n");
2969 
2970  break;
2971  case CullFaceAttrib::M_cull_clockwise:
2972  set_render_state(D3DRS_CULLMODE, D3DCULL_CW);
2973 
2974 // printf ("------------------- D3DCULL_CW -- CLOCKWISE \n");
2975 
2976  break;
2977  case CullFaceAttrib::M_cull_counter_clockwise:
2978  set_render_state(D3DRS_CULLMODE, D3DCULL_CCW);
2979 
2980 // printf ("------------------- D3DCULL_CCW\n");
2981 
2982  break;
2983  default:
2984  dxgsg9_cat.error()
2985  << "invalid cull face mode " << (int)_cull_face_mode << endl;
2986  break;
2987  }
2988 }
2989 
2990 /**
2991  *
2992  */
2993 void DXGraphicsStateGuardian9::
2994 do_issue_fog() {
2995  const FogAttrib *target_fog = DCAST(FogAttrib, _target_rs->get_attrib_def(FogAttrib::get_class_slot()));
2996  if (!target_fog->is_off()) {
2997  set_render_state(D3DRS_FOGENABLE, TRUE);
2998  Fog *fog = target_fog->get_fog();
2999  nassertv(fog != nullptr);
3000  apply_fog(fog);
3001  } else {
3002  set_render_state(D3DRS_FOGENABLE, FALSE);
3003  }
3004 }
3005 
3006 /**
3007  *
3008  */
3009 void DXGraphicsStateGuardian9::
3010 do_issue_depth_offset() {
3011  const DepthOffsetAttrib *target_depth_offset = DCAST(DepthOffsetAttrib, _target_rs->get_attrib_def(DepthOffsetAttrib::get_class_slot()));
3012  int offset = target_depth_offset->get_offset();
3013 
3014  if (_supports_depth_bias && !dx_broken_depth_bias) {
3015  set_render_state(D3DRS_DEPTHBIAS, offset);
3016  set_render_state(D3DRS_SLOPESCALEDEPTHBIAS, offset);
3017 
3018  } else {
3019  // DirectX depth bias isn't directly supported by the driver. Cheese a
3020  // depth bias effect by sliding the viewport backward a bit.
3021  static const PN_stdfloat bias_scale = dx_depth_bias_scale;
3022  D3DVIEWPORT9 vp = _current_viewport;
3023  vp.MinZ -= bias_scale * offset;
3024  vp.MaxZ -= bias_scale * offset;
3025  _d3d_device->SetViewport(&vp);
3026  }
3027 }
3028 
3029 /**
3030  *
3031  */
3032 void DXGraphicsStateGuardian9::
3033 do_issue_shade_model() {
3034  const ShadeModelAttrib *target_shade_model = DCAST(ShadeModelAttrib, _target_rs->get_attrib_def(ShadeModelAttrib::get_class_slot()));
3035  switch (target_shade_model->get_mode()) {
3036  case ShadeModelAttrib::M_smooth:
3037  set_render_state(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
3038  break;
3039 
3040  case ShadeModelAttrib::M_flat:
3041  set_render_state(D3DRS_SHADEMODE, D3DSHADE_FLAT);
3042  break;
3043  }
3044 }
3045 
3046 /**
3047  * Simultaneously resets the render state and the transform state.
3048  *
3049  * This transform specified is the "internal" net transform, already converted
3050  * into the GSG's internal coordinate space by composing it to
3051  * get_cs_transform(). (Previously, this used to be the "external" net
3052  * transform, with the assumption that that GSG would convert it internally,
3053  * but that is no longer the case.)
3054  *
3055  * Special case: if (state==NULL), then the target state is already stored in
3056  * _target.
3057  */
3060  const TransformState *transform) {
3061 #ifndef NDEBUG
3062  if (gsg_cat.is_spam()) {
3063  gsg_cat.spam() << "Setting GSG state to " << (void *)target << ":\n";
3064  target->write(gsg_cat.spam(false), 2);
3065  }
3066 #endif
3067  _state_pcollector.add_level(1);
3068  PStatTimer timer1(_draw_set_state_pcollector);
3069 
3070  if (transform != _internal_transform) {
3071  // PStatTimer timer(_draw_set_state_transform_pcollector);
3072  _state_pcollector.add_level(1);
3073  _internal_transform = transform;
3074  do_issue_transform();
3075  }
3076 
3077  if (target == _state_rs && (_state_mask | _inv_state_mask).is_all_on()) {
3078  return;
3079  }
3080  _target_rs = target;
3081 
3082  determine_target_shader();
3083 
3084  int alpha_test_slot = AlphaTestAttrib::get_class_slot();
3085  if (_target_rs->get_attrib(alpha_test_slot) != _state_rs->get_attrib(alpha_test_slot) ||
3086  !_state_mask.get_bit(alpha_test_slot)) {
3087  // PStatTimer timer(_draw_set_state_alpha_test_pcollector);
3088  do_issue_alpha_test();
3089  _state_mask.set_bit(alpha_test_slot);
3090  }
3091 
3092  int clip_plane_slot = ClipPlaneAttrib::get_class_slot();
3093  if (_target_rs->get_attrib(clip_plane_slot) != _state_rs->get_attrib(clip_plane_slot) ||
3094  !_state_mask.get_bit(clip_plane_slot)) {
3095  // PStatTimer timer(_draw_set_state_clip_plane_pcollector);
3096  do_issue_clip_plane();
3097  _state_mask.set_bit(clip_plane_slot);
3098  }
3099 
3100  int color_slot = ColorAttrib::get_class_slot();
3101  int color_scale_slot = ColorScaleAttrib::get_class_slot();
3102  if (_target_rs->get_attrib(color_slot) != _state_rs->get_attrib(color_slot) ||
3103  _target_rs->get_attrib(color_scale_slot) != _state_rs->get_attrib(color_scale_slot) ||
3104  !_state_mask.get_bit(color_slot) ||
3105  !_state_mask.get_bit(color_scale_slot)) {
3106  // PStatTimer timer(_draw_set_state_color_pcollector);
3107  do_issue_color();
3108  do_issue_color_scale();
3109  _state_mask.set_bit(color_slot);
3110  _state_mask.set_bit(color_scale_slot);
3111  if (_current_shader_context) {
3112  _current_shader_context->issue_parameters(this, Shader::SSD_color);
3113  _current_shader_context->issue_parameters(this, Shader::SSD_colorscale);
3114  }
3115  }
3116 
3117  int cull_face_slot = CullFaceAttrib::get_class_slot();
3118  if (_target_rs->get_attrib(cull_face_slot) != _state_rs->get_attrib(cull_face_slot) ||
3119  !_state_mask.get_bit(cull_face_slot)) {
3120  // PStatTimer timer(_draw_set_state_cull_face_pcollector);
3121  do_issue_cull_face();
3122  _state_mask.set_bit(cull_face_slot);
3123  }
3124 
3125  int depth_offset_slot = DepthOffsetAttrib::get_class_slot();
3126  if (_target_rs->get_attrib(depth_offset_slot) != _state_rs->get_attrib(depth_offset_slot) ||
3127  !_state_mask.get_bit(depth_offset_slot)) {
3128  // PStatTimer timer(_draw_set_state_depth_offset_pcollector);
3129  do_issue_depth_offset();
3130  _state_mask.set_bit(depth_offset_slot);
3131  }
3132 
3133  int depth_test_slot = DepthTestAttrib::get_class_slot();
3134  if (_target_rs->get_attrib(depth_test_slot) != _state_rs->get_attrib(depth_test_slot) ||
3135  !_state_mask.get_bit(depth_test_slot)) {
3136  // PStatTimer timer(_draw_set_state_depth_test_pcollector);
3137  do_issue_depth_test();
3138  _state_mask.set_bit(depth_test_slot);
3139  }
3140 
3141  int depth_write_slot = DepthWriteAttrib::get_class_slot();
3142  if (_target_rs->get_attrib(depth_write_slot) != _state_rs->get_attrib(depth_write_slot) ||
3143  !_state_mask.get_bit(depth_write_slot)) {
3144  // PStatTimer timer(_draw_set_state_depth_write_pcollector);
3145  do_issue_depth_write();
3146  _state_mask.set_bit(depth_write_slot);
3147  }
3148 
3149  int render_mode_slot = RenderModeAttrib::get_class_slot();
3150  if (_target_rs->get_attrib(render_mode_slot) != _state_rs->get_attrib(render_mode_slot) ||
3151  !_state_mask.get_bit(render_mode_slot)) {
3152  // PStatTimer timer(_draw_set_state_render_mode_pcollector);
3153  do_issue_render_mode();
3154  _state_mask.set_bit(render_mode_slot);
3155  }
3156 
3157  int rescale_normal_slot = RescaleNormalAttrib::get_class_slot();
3158  if (_target_rs->get_attrib(rescale_normal_slot) != _state_rs->get_attrib(rescale_normal_slot) ||
3159  !_state_mask.get_bit(rescale_normal_slot)) {
3160  // PStatTimer timer(_draw_set_state_rescale_normal_pcollector);
3161  do_issue_rescale_normal();
3162  _state_mask.set_bit(rescale_normal_slot);
3163  }
3164 
3165  int shade_model_slot = ShadeModelAttrib::get_class_slot();
3166  if (_target_rs->get_attrib(shade_model_slot) != _state_rs->get_attrib(shade_model_slot) ||
3167  !_state_mask.get_bit(shade_model_slot)) {
3168  // PStatTimer timer(_draw_set_state_shade_model_pcollector);
3169  do_issue_shade_model();
3170  _state_mask.set_bit(shade_model_slot);
3171  }
3172 
3173  int transparency_slot = TransparencyAttrib::get_class_slot();
3174  int color_write_slot = ColorWriteAttrib::get_class_slot();
3175  int color_blend_slot = ColorBlendAttrib::get_class_slot();
3176  if (_target_rs->get_attrib(transparency_slot) != _state_rs->get_attrib(transparency_slot) ||
3177  _target_rs->get_attrib(color_write_slot) != _state_rs->get_attrib(color_write_slot) ||
3178  _target_rs->get_attrib(color_blend_slot) != _state_rs->get_attrib(color_blend_slot) ||
3179  !_state_mask.get_bit(transparency_slot) ||
3180  !_state_mask.get_bit(color_write_slot) ||
3181  !_state_mask.get_bit(color_blend_slot) ||
3182  (_target_shader->get_flag(ShaderAttrib::F_disable_alpha_write) !=
3183  _state_shader->get_flag(ShaderAttrib::F_disable_alpha_write))) {
3184  // PStatTimer timer(_draw_set_state_blending_pcollector);
3185  do_issue_blending();
3186  _state_mask.set_bit(transparency_slot);
3187  _state_mask.set_bit(color_write_slot);
3188  _state_mask.set_bit(color_blend_slot);
3189  }
3190 
3191  if (_target_shader != _state_shader) {
3192  // PStatTimer timer(_draw_set_state_shader_pcollector);
3193  do_issue_shader();
3194  _state_shader = _target_shader;
3195  _state_mask.clear_bit(TextureAttrib::get_class_slot());
3196  }
3197 
3198  int texture_slot = TextureAttrib::get_class_slot();
3199  int tex_matrix_slot = TexMatrixAttrib::get_class_slot();
3200  int tex_gen_slot = TexGenAttrib::get_class_slot();
3201  if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) ||
3202  _target_rs->get_attrib(tex_matrix_slot) != _state_rs->get_attrib(tex_matrix_slot) ||
3203  _target_rs->get_attrib(tex_gen_slot) != _state_rs->get_attrib(tex_gen_slot) ||
3204  !_state_mask.get_bit(texture_slot) ||
3205  !_state_mask.get_bit(tex_matrix_slot) ||
3206  !_state_mask.get_bit(tex_gen_slot)) {
3207  // PStatTimer timer(_draw_set_state_texture_pcollector);
3208  determine_target_texture();
3209  do_issue_texture();
3210 
3211  _state_texture = _target_texture;
3212  _state_mask.set_bit(texture_slot);
3213  _state_mask.set_bit(tex_matrix_slot);
3214  _state_mask.set_bit(tex_gen_slot);
3215  }
3216 
3217  int material_slot = MaterialAttrib::get_class_slot();
3218  if (_target_rs->get_attrib(material_slot) != _state_rs->get_attrib(material_slot) ||
3219  !_state_mask.get_bit(material_slot)) {
3220  // PStatTimer timer(_draw_set_state_material_pcollector);
3221  do_issue_material();
3222  _state_mask.set_bit(material_slot);
3223  if (_current_shader_context) {
3224  _current_shader_context->issue_parameters(this, Shader::SSD_material);
3225  }
3226  }
3227 
3228  int light_slot = LightAttrib::get_class_slot();
3229  if (_target_rs->get_attrib(light_slot) != _state_rs->get_attrib(light_slot) ||
3230  !_state_mask.get_bit(light_slot)) {
3231  // PStatTimer timer(_draw_set_state_light_pcollector);
3232  do_issue_light();
3233  _state_mask.set_bit(light_slot);
3234  }
3235 
3236  int stencil_slot = StencilAttrib::get_class_slot();
3237  if (_target_rs->get_attrib(stencil_slot) != _state_rs->get_attrib(stencil_slot) ||
3238  !_state_mask.get_bit(stencil_slot)) {
3239  // PStatTimer timer(_draw_set_state_stencil_pcollector);
3240  do_issue_stencil();
3241  _state_mask.set_bit(stencil_slot);
3242  }
3243 
3244  int fog_slot = FogAttrib::get_class_slot();
3245  if (_target_rs->get_attrib(fog_slot) != _state_rs->get_attrib(fog_slot) ||
3246  !_state_mask.get_bit(fog_slot)) {
3247  // PStatTimer timer(_draw_set_state_fog_pcollector);
3248  do_issue_fog();
3249  _state_mask.set_bit(fog_slot);
3250  if (_current_shader_context) {
3251  _current_shader_context->issue_parameters(this, Shader::SSD_fog);
3252  }
3253  }
3254 
3255  int scissor_slot = ScissorAttrib::get_class_slot();
3256  if (_target_rs->get_attrib(scissor_slot) != _state_rs->get_attrib(scissor_slot) ||
3257  !_state_mask.get_bit(scissor_slot)) {
3258  // PStatTimer timer(_draw_set_state_scissor_pcollector);
3259  do_issue_scissor();
3260  _state_mask.set_bit(scissor_slot);
3261  }
3262 
3263  _state_rs = _target_rs;
3264 }
3265 
3266 /**
3267  * Called the first time a particular light has been bound to a given id
3268  * within a frame, this should set up the associated hardware light with the
3269  * light's properties.
3270  */
3272 bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
3273  // Get the light in "world coordinates" (actually, view coordinates). This
3274  // means the light in the coordinate space of the camera, converted to DX's
3275  // coordinate system.
3276  CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
3277  const LMatrix4 &light_mat = transform->get_mat();
3278  LMatrix4 rel_mat = light_mat * LMatrix4::convert_mat(CS_yup_left, CS_default);
3279  LPoint3f pos = LCAST(float, light_obj->get_point() * rel_mat);
3280 
3281  D3DCOLORVALUE black;
3282  black.r = black.g = black.b = black.a = 0.0f;
3283  D3DLIGHT9 alight;
3284  alight.Type = D3DLIGHT_POINT;
3285  alight.Diffuse = get_light_color(light_obj);
3286  alight.Ambient = black ;
3287  LColorf color = LCAST(float, light_obj->get_specular_color());
3288  alight.Specular = *(D3DCOLORVALUE *)(color.get_data());
3289 
3290  // Position needs to specify x, y, z, and w w == 1 implies non-infinite
3291  // position
3292  alight.Position = *(D3DVECTOR *)pos.get_data();
3293 
3294  alight.Range = __D3DLIGHT_RANGE_MAX;
3295  alight.Falloff = 1.0f;
3296 
3297  const LVecBase3 &att = light_obj->get_attenuation();
3298  alight.Attenuation0 = att[0];
3299  alight.Attenuation1 = att[1];
3300  alight.Attenuation2 = att[2];
3301 
3302  HRESULT hr = _d3d_device->SetLight(light_id, &alight);
3303  if (FAILED(hr)) {
3304  wdxdisplay9_cat.warning()
3305  << "Could not set light properties for " << light
3306  << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n";
3307  }
3308 }
3309 
3310 /**
3311  * Called the first time a particular light has been bound to a given id
3312  * within a frame, this should set up the associated hardware light with the
3313  * light's properties.
3314  */
3316 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
3317  static PStatCollector _draw_set_state_light_bind_directional_pcollector("Draw:Set State:Light:Bind:Directional");
3318  // PStatTimer timer(_draw_set_state_light_bind_directional_pcollector);
3319 
3320  std::pair<DirectionalLights::iterator, bool> lookup = _dlights.insert(DirectionalLights::value_type(light, D3DLIGHT9()));
3321  D3DLIGHT9 &fdata = (*lookup.first).second;
3322  if (lookup.second) {
3323  // Get the light in "world coordinates" (actually, view coordinates).
3324  // This means the light in the coordinate space of the camera, converted
3325  // to DX's coordinate system.
3326  CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
3327  const LMatrix4 &light_mat = transform->get_mat();
3328  LMatrix4 rel_mat = light_mat * LMatrix4::convert_mat(CS_yup_left, CS_default);
3329  LVector3f dir = LCAST(float, light_obj->get_direction() * rel_mat);
3330 
3331  D3DCOLORVALUE black;
3332  black.r = black.g = black.b = black.a = 0.0f;
3333 
3334  ZeroMemory(&fdata, sizeof(D3DLIGHT9));
3335 
3336  fdata.Type = D3DLIGHT_DIRECTIONAL;
3337  fdata.Ambient = black ;
3338  LColorf color = LCAST(float, light_obj->get_specular_color());
3339  fdata.Specular = *(D3DCOLORVALUE *)(color.get_data());
3340 
3341  fdata.Direction = *(D3DVECTOR *)dir.get_data();
3342 
3343  fdata.Range = __D3DLIGHT_RANGE_MAX;
3344  fdata.Falloff = 1.0f;
3345 
3346  fdata.Attenuation0 = 1.0f; // constant
3347  fdata.Attenuation1 = 0.0f; // linear
3348  fdata.Attenuation2 = 0.0f; // quadratic
3349  }
3350 
3351  // We have to reset the Diffuse color at each call, because it might have
3352  // changed independently of the light object itself (due to
3353  // color_scale_via_lighting being in effect).
3354  fdata.Diffuse = get_light_color(light_obj);
3355 
3356  HRESULT hr = _d3d_device->SetLight(light_id, &fdata);
3357  if (FAILED(hr)) {
3358  wdxdisplay9_cat.warning()
3359  << "Could not set light properties for " << light
3360  << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n";
3361  }
3362 }
3363 
3364 /**
3365  * Called the first time a particular light has been bound to a given id
3366  * within a frame, this should set up the associated hardware light with the
3367  * light's properties.
3368  */
3370 bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
3371  Lens *lens = light_obj->get_lens();
3372  nassertv(lens != nullptr);
3373 
3374  // Get the light in "world coordinates" (actually, view coordinates). This
3375  // means the light in the coordinate space of the camera, converted to DX's
3376  // coordinate system.
3377  CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
3378  const LMatrix4 &light_mat = transform->get_mat();
3379  LMatrix4 rel_mat = light_mat * LMatrix4::convert_mat(CS_yup_left, CS_default);
3380  LPoint3f pos = LCAST(float, lens->get_nodal_point() * rel_mat);
3381  LVector3f dir = LCAST(float, lens->get_view_vector() * rel_mat);
3382 
3383  D3DCOLORVALUE black;
3384  black.r = black.g = black.b = black.a = 0.0f;
3385 
3386  D3DLIGHT9 alight;
3387  ZeroMemory(&alight, sizeof(D3DLIGHT9));
3388 
3389  alight.Type = D3DLIGHT_SPOT;
3390  alight.Ambient = black ;
3391  alight.Diffuse = get_light_color(light_obj);
3392  LColorf color = LCAST(float, light_obj->get_specular_color());
3393  alight.Specular = *(D3DCOLORVALUE *)(color.get_data());
3394 
3395  alight.Position = *(D3DVECTOR *)pos.get_data();
3396 
3397  alight.Direction = *(D3DVECTOR *)dir.get_data();
3398 
3399  alight.Range = __D3DLIGHT_RANGE_MAX;
3400 
3401  // I determined this formular empirically. It seems to mostly approximate
3402  // the OpenGL spotlight equation, for a reasonable range of values for FOV.
3403  PN_stdfloat fov = lens->get_hfov();
3404  alight.Falloff = light_obj->get_exponent() * (fov * fov * fov) / 1620000.0f;
3405 
3406  alight.Theta = 0.0f;
3407  alight.Phi = deg_2_rad(fov);
3408 
3409  const LVecBase3 &att = light_obj->get_attenuation();
3410  alight.Attenuation0 = att[0];
3411  alight.Attenuation1 = att[1];
3412  alight.Attenuation2 = att[2];
3413 
3414  HRESULT hr = _d3d_device->SetLight(light_id, &alight);
3415  if (FAILED(hr)) {
3416  wdxdisplay9_cat.warning()
3417  << "Could not set light properties for " << light
3418  << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n";
3419  }
3420 }
3421 
3422 /**
3423  * Maps from the Geom's internal numeric type symbols to DirectX's.
3424  */
3426 get_index_type(Geom::NumericType numeric_type) {
3427  switch (numeric_type) {
3428  // NT_uint8 is automatically promoted to uint16.
3429  case Geom::NT_uint8:
3430  case Geom::NT_uint16:
3431  return D3DFMT_INDEX16;
3432 
3433  case Geom::NT_uint32:
3434  return D3DFMT_INDEX32;
3435  }
3436 
3437  dxgsg9_cat.error()
3438  << "Invalid index NumericType value (" << (int)numeric_type << ")\n";
3439  return D3DFMT_INDEX16;
3440 }
3441 
3442 /**
3443  *
3444  */
3445 void DXGraphicsStateGuardian9::
3446 do_issue_material() {
3447  static Material empty;
3448  const Material *material;
3449  const MaterialAttrib *target_material = DCAST(MaterialAttrib, _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()));
3450  if (target_material->is_off()) {
3451  material = &empty;
3452  } else {
3453  material = target_material->get_material();
3454  }
3455 
3456  D3DMATERIAL9 cur_material;
3457  LColorf color = LCAST(float, material->get_diffuse());
3458  cur_material.Diffuse = *(D3DCOLORVALUE *)(color.get_data());
3459  color = LCAST(float, material->get_ambient());
3460  cur_material.Ambient = *(D3DCOLORVALUE *)(color.get_data());
3461  color = LCAST(float, material->get_specular());
3462  cur_material.Specular = *(D3DCOLORVALUE *)(color.get_data());
3463  color = LCAST(float, material->get_emission());
3464  cur_material.Emissive = *(D3DCOLORVALUE *)(color.get_data());
3465  cur_material.Power = material->get_shininess();
3466 
3467  if (material->has_diffuse() || material->has_base_color()) {
3468  // If the material specifies an diffuse color, use it.
3469  set_render_state(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
3470  } else {
3471  // Otherwise, the diffuse color comes from the object color.
3472  if (_has_material_force_color) {
3473  color = LCAST(float, _material_force_color);
3474  cur_material.Diffuse = *(D3DCOLORVALUE *)color.get_data();
3475  set_render_state(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
3476  } else {
3477  set_render_state(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
3478  }
3479  }
3480  if (material->has_ambient() || material->has_base_color()) {
3481  // If the material specifies an ambient color, use it.
3482  set_render_state(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
3483  } else {
3484  // Otherwise, the ambient color comes from the object color.
3485  if (_has_material_force_color) {
3486  color = LCAST(float, _material_force_color);
3487  cur_material.Ambient = *(D3DCOLORVALUE *)color.get_data();
3488  set_render_state(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
3489  } else {
3490  set_render_state(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1);
3491  }
3492  }
3493 
3494  if (material->has_specular() || material->has_base_color()) {
3495  set_render_state(D3DRS_SPECULARENABLE, TRUE);
3496  } else {
3497  set_render_state(D3DRS_SPECULARENABLE, FALSE);
3498  }
3499 
3500  if (material->get_local()) {
3501  set_render_state(D3DRS_LOCALVIEWER, TRUE);
3502  } else {
3503  set_render_state(D3DRS_LOCALVIEWER, FALSE);
3504  }
3505 
3506  _d3d_device->SetMaterial(&cur_material);
3507 }
3508 
3509 /**
3510  *
3511  */
3512 void DXGraphicsStateGuardian9::
3513 do_issue_texture() {
3514  DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
3515 
3516  if (_texture_binding_shader_context==0) {
3517  if (_current_shader_context==0) {
3518  update_standard_texture_bindings();
3519  } else {
3520  disable_standard_texture_bindings();
3521  _current_shader_context->update_shader_texture_bindings(nullptr,this);
3522  }
3523  } else {
3524  if (_current_shader_context==0) {
3525  _texture_binding_shader_context->disable_shader_texture_bindings(this);
3526  update_standard_texture_bindings();
3527  } else {
3528  _current_shader_context->
3529  update_shader_texture_bindings(_texture_binding_shader_context,this);
3530  }
3531  }
3532  _texture_binding_shader = _current_shader;
3533  _texture_binding_shader_context = _current_shader_context;
3534 }
3535 
3536 /**
3537  *
3538  */
3539 void DXGraphicsStateGuardian9::
3540 disable_standard_texture_bindings() {
3541  // Disable the texture stages that are no longer used.
3542  for (int i = 0; i < _num_active_texture_stages; i++) {
3543  HRESULT hr;
3544 
3545  hr = _d3d_device -> SetTexture (i, nullptr);
3546  if (FAILED (hr)) {
3547  dxgsg9_cat.error()
3548  << "SetTexture ("
3549  << i
3550  << ", NULL) failed "
3551  << D3DERRORSTRING(hr);
3552  }
3553  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
3554  }
3555 
3556  _num_active_texture_stages = 0;
3557 }
3558 
3559 /**
3560  *
3561  */
3562 void DXGraphicsStateGuardian9::
3563 update_standard_texture_bindings() {
3564  DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
3565 
3566  int num_stages = _target_texture->get_num_on_ff_stages();
3567  int num_old_stages = _max_texture_stages;
3568  if (_state_texture != nullptr) {
3569  num_old_stages = _state_texture->get_num_on_ff_stages();
3570  }
3571 
3572  nassertv(num_stages <= _max_texture_stages &&
3573  _num_active_texture_stages <= _max_texture_stages);
3574 
3575  _texture_involves_color_scale = false;
3576 
3577  // We have to match up the texcoord stage index to the order written out by
3578  // the DXGeomMunger. This means the texcoord names are written in the order
3579  // indicated by the TextureAttrib.
3580 
3581  int si;
3582  for (si = 0; si < num_stages; si++) {
3583  TextureStage *stage = _target_texture->get_on_ff_stage(si);
3584  int texcoord_index = _target_texture->get_ff_tc_index(si);
3585 
3586  Texture *texture = _target_texture->get_on_texture(stage);
3587  nassertv(texture != nullptr);
3588  const SamplerState &sampler = _target_texture->get_on_sampler(stage);
3589 
3590  // We always reissue every stage in DX, just in case the texcoord index or
3591  // texgen mode or some other property has changed.
3592  int view = get_current_tex_view_offset() + stage->get_tex_view_offset();
3593  TextureContext *tc = texture->prepare_now(view, _prepared_objects, this);
3594  apply_texture(si, tc, sampler);
3595  set_texture_blend_mode(si, stage);
3596 
3597  int texcoord_dimensions = 2;
3598 
3599  CPT(TransformState) tex_mat = TransformState::make_identity();
3600  const TexMatrixAttrib *target_tex_matrix = DCAST(TexMatrixAttrib, _target_rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
3601  if (target_tex_matrix->has_stage(stage)) {
3602  tex_mat = target_tex_matrix->get_transform(stage);
3603  }
3604 
3605  // Issue the texgen mode.
3606  TexGenAttrib::Mode mode = _target_tex_gen->get_mode(stage);
3607  bool any_point_sprite = false;
3608 
3609  switch (mode) {
3610  case TexGenAttrib::M_off:
3611  case TexGenAttrib::M_unused2:
3612  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX, texcoord_index);
3613  break;
3614 
3615  case TexGenAttrib::M_eye_sphere_map:
3616  {
3617  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3618  texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
3619  // This texture matrix, applied on top of the texcoord computed by
3620  // D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR, approximates the effect
3621  // produced by OpenGL's GL_SPHERE_MAP.
3622  static CPT(TransformState) sphere_map =
3623  TransformState::make_mat(LMatrix4(0.33, 0.0f, 0.0f, 0.0f,
3624  0.0f, 0.33, 0.0f, 0.0f,
3625  0.0f, 0.0f, 1.0f, 0.0f,
3626  0.5f, 0.5f, 0.0f, 1.0f));
3627  tex_mat = tex_mat->compose(sphere_map);
3628  texcoord_dimensions = 3;
3629  }
3630  break;
3631 
3632  case TexGenAttrib::M_world_cube_map:
3633  // To achieve world reflection vector, we must transform camera
3634  // coordinates to world coordinates; i.e. apply the camera transform.
3635  // In the case of a vector, we should not apply the pos component of the
3636  // transform.
3637  {
3638  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3639  texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
3640  texcoord_dimensions = 3;
3641  CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
3642  tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3::zero()));
3643  }
3644  break;
3645 
3646  case TexGenAttrib::M_eye_cube_map:
3647  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3648  texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
3649  tex_mat = tex_mat->compose(_inv_cs_transform);
3650  texcoord_dimensions = 3;
3651  break;
3652 
3653  case TexGenAttrib::M_world_normal:
3654  // To achieve world normal, we must transform camera coordinates to
3655  // world coordinates; i.e. apply the camera transform. In the case of
3656  // a normal, we should not apply the pos component of the transform.
3657  {
3658  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3659  texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
3660  texcoord_dimensions = 3;
3661  CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
3662  tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3::zero()));
3663  }
3664  break;
3665 
3666  case TexGenAttrib::M_eye_normal:
3667  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3668  texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
3669  texcoord_dimensions = 3;
3670  tex_mat = tex_mat->compose(_inv_cs_transform);
3671  break;
3672 
3673  case TexGenAttrib::M_world_position:
3674  // To achieve world position, we must transform camera coordinates to
3675  // world coordinates; i.e. apply the camera transform.
3676  {
3677  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3678  texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
3679  texcoord_dimensions = 3;
3680  CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
3681  tex_mat = tex_mat->compose(camera_transform);
3682  }
3683  break;
3684 
3685  case TexGenAttrib::M_eye_position:
3686  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3687  texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
3688  texcoord_dimensions = 3;
3689  tex_mat = tex_mat->compose(_inv_cs_transform);
3690  break;
3691 
3692  case TexGenAttrib::M_point_sprite:
3693  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX, texcoord_index);
3694  any_point_sprite = true;
3695  break;
3696 
3697  case TexGenAttrib::M_constant:
3698  // To generate a constant UV(w) coordinate everywhere, we use
3699  // CAMERASPACEPOSITION coordinates, but we construct a special matrix
3700  // that flattens the existing values to zero and then adds our desired
3701  // value.
3702 
3703  // The only reason we need to specify CAMERASPACEPOSITION at all,
3704  // instead of using whatever texture coordinates (if any) happen to be
3705  // on the vertices, is because we need to guarantee that there are 3-d
3706  // texture coordinates, because of the 3-component texture coordinate in
3707  // get_constant_value().
3708  {
3709  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3710  texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
3711  texcoord_dimensions = 3;
3712 
3713  const LTexCoord3 &v = _target_tex_gen->get_constant_value(stage);
3714  CPT(TransformState) squash =
3715  TransformState::make_pos_hpr_scale(v, LVecBase3::zero(),
3716  LVecBase3::zero());
3717  tex_mat = tex_mat->compose(squash);
3718  }
3719  break;
3720  }
3721 
3722  set_render_state(D3DRS_POINTSPRITEENABLE, any_point_sprite);
3723 
3724  if (!tex_mat->is_identity()) {
3725  if (/*tex_mat->is_2d() &&*/ texcoord_dimensions <= 2) {
3726  // For 2-d texture coordinates, we have to reorder the matrix.
3727  LMatrix4 m = tex_mat->get_mat();
3728  LMatrix4f mf;
3729  mf.set(m(0, 0), m(0, 1), m(0, 3), 0.0f,
3730  m(1, 0), m(1, 1), m(1, 3), 0.0f,
3731  m(3, 0), m(3, 1), m(3, 3), 0.0f,
3732  0.0f, 0.0f, 0.0f, 1.0f);
3733  _d3d_device->SetTransform(get_tex_mat_sym(si), (D3DMATRIX *)mf.get_data());
3734  set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
3735  D3DTTFF_COUNT2);
3736  } else {
3737  LMatrix4f mf = LCAST(float, tex_mat->get_mat());
3738  _d3d_device->SetTransform(get_tex_mat_sym(si), (D3DMATRIX *)mf.get_data());
3739  DWORD transform_flags = texcoord_dimensions;
3740  if (mf.get_col(3) != LVecBase4f(0.0f, 0.0f, 0.0f, 1.0f)) {
3741  // If we have a projected texture matrix, we also need to set
3742  // D3DTTFF_COUNT4.
3743  transform_flags = D3DTTFF_COUNT4 | D3DTTFF_PROJECTED;
3744  }
3745  set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
3746  transform_flags);
3747  }
3748 
3749  } else {
3750  set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
3751  D3DTTFF_DISABLE);
3752  // For some reason, "disabling" texture coordinate transforms doesn't
3753  // seem to be sufficient. We'll load an identity matrix to underscore
3754  // the point.
3755  _d3d_device->SetTransform(get_tex_mat_sym(si), &_d3d_ident_mat);
3756  }
3757  }
3758 
3759  // Disable the texture stages that are no longer used.
3760  for (si = num_stages; si < _num_active_texture_stages; si++) {
3761  set_texture_stage_state(si, D3DTSS_COLOROP, D3DTOP_DISABLE);
3762  _d3d_device->SetTexture(si, nullptr);
3763  }
3764 
3765  // Save the count of texture stages for next time.
3766  _num_active_texture_stages = num_stages;
3767 }
3768 
3769 /**
3770  * Called after any of the things that might change blending state have
3771  * changed, this function is responsible for setting the appropriate color
3772  * blending mode based on the current properties.
3773  */
3774 void DXGraphicsStateGuardian9::
3775 do_issue_blending() {
3776  // Handle the color_write attrib. If color_write is off, then all the other
3777  // blending-related stuff doesn't matter. If the device doesn't support
3778  // color-write, we use blending tricks to effectively disable color write.
3779  const ColorWriteAttrib *target_color_write = DCAST(ColorWriteAttrib, _target_rs->get_attrib_def(ColorWriteAttrib::get_class_slot()));
3780  unsigned int color_channels =
3781  target_color_write->get_channels() & _color_write_mask;
3782  if (_target_shader->get_flag(ShaderAttrib::F_disable_alpha_write)) {
3783  color_channels &= ~(ColorWriteAttrib::C_alpha);
3784  }
3785  if (color_channels == ColorWriteAttrib::C_off) {
3786  if (_screen->_can_direct_disable_color_writes) {
3787  set_render_state(D3DRS_ALPHABLENDENABLE, FALSE);
3788  set_render_state(D3DRS_COLORWRITEENABLE, (DWORD)0x0);
3789  } else {
3790  set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
3791  set_render_state(D3DRS_SRCBLEND, D3DBLEND_ZERO);
3792  set_render_state(D3DRS_DESTBLEND, D3DBLEND_ONE);
3793  }
3794  return;
3795  } else {
3796  if (_screen->_can_direct_disable_color_writes) {
3797  set_render_state(D3DRS_COLORWRITEENABLE, color_channels);
3798  }
3799  }
3800 
3801  const ColorBlendAttrib *color_blend;
3802  _target_rs->get_attrib_def(color_blend);
3803  ColorBlendAttrib::Mode color_blend_mode = color_blend->get_mode();
3804 
3805  const TransparencyAttrib *target_transparency;
3806  _target_rs->get_attrib_def(target_transparency);
3807  TransparencyAttrib::Mode transparency_mode = target_transparency->get_mode();
3808 
3809  // Is there a color blend set?
3810  if (color_blend_mode != ColorBlendAttrib::M_none) {
3811  set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
3812  set_render_state(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
3813  set_render_state(D3DRS_BLENDOP, get_blend_mode(color_blend_mode));
3814  set_render_state(D3DRS_BLENDOPALPHA, get_blend_mode(color_blend->get_alpha_mode()));
3815  set_render_state(D3DRS_SRCBLEND, get_blend_func(color_blend->get_operand_a()));
3816  set_render_state(D3DRS_DESTBLEND, get_blend_func(color_blend->get_operand_b()));
3817  set_render_state(D3DRS_SRCBLENDALPHA, get_blend_func(color_blend->get_alpha_operand_a()));
3818  set_render_state(D3DRS_DESTBLENDALPHA, get_blend_func(color_blend->get_alpha_operand_b()));
3819  return;
3820  }
3821 
3822  // No color blend; is there a transparency set?
3823  switch (transparency_mode) {
3824  case TransparencyAttrib::M_none:
3825  case TransparencyAttrib::M_binary:
3826  break;
3827 
3828  case TransparencyAttrib::M_alpha:
3829  case TransparencyAttrib::M_multisample:
3830  case TransparencyAttrib::M_multisample_mask:
3831  case TransparencyAttrib::M_dual:
3832  set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
3833  if (old_alpha_blend) {
3834  set_render_state(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
3835  } else {
3836  set_render_state(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
3837  set_render_state(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD);
3838  set_render_state(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
3839  set_render_state(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
3840  }
3841  set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
3842  set_render_state(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
3843  set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
3844  return;
3845 
3846  case TransparencyAttrib::M_premultiplied_alpha:
3847  set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
3848  set_render_state(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
3849  set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
3850  set_render_state(D3DRS_SRCBLEND, D3DBLEND_ONE);
3851  set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
3852  return;
3853 
3854  default:
3855  dxgsg9_cat.error()
3856  << "invalid transparency mode " << (int)transparency_mode << endl;
3857  break;
3858  }
3859 
3860  // Nothing's set, so disable blending.
3861  set_render_state(D3DRS_ALPHABLENDENABLE, FALSE);
3862 }
3863 
3864 /**
3865  * Called by clear_state_and_transform() to ensure that the current modelview
3866  * and projection matrices are properly loaded in the graphics state, after a
3867  * callback might have mucked them up.
3868  */
3869 void DXGraphicsStateGuardian9::
3870 reissue_transforms() {
3871  prepare_lens();
3872  do_issue_transform();
3873 }
3874 
3875 /**
3876  * Intended to be overridden by a derived class to enable or disable the use
3877  * of lighting overall. This is called by issue_light() according to whether
3878  * any lights are in use or not.
3879  */
3880 void DXGraphicsStateGuardian9::
3881 enable_lighting(bool enable) {
3882  set_render_state(D3DRS_LIGHTING, (DWORD)enable);
3883 }
3884 
3885 /**
3886  * Intended to be overridden by a derived class to indicate the color of the
3887  * ambient light that should be in effect. This is called by issue_light()
3888  * after all other lights have been enabled or disabled.
3889  */
3890 void DXGraphicsStateGuardian9::
3891 set_ambient_light(const LColor &color) {
3892  LColor c = color;
3893  c.set(c[0] * _light_color_scale[0],
3894  c[1] * _light_color_scale[1],
3895  c[2] * _light_color_scale[2],
3896  c[3] * _light_color_scale[3]);
3897 
3898  set_render_state(D3DRS_AMBIENT, LColor_to_D3DCOLOR(c));
3899 }
3900 
3901 /**
3902  * Intended to be overridden by a derived class to enable the indicated light
3903  * id. A specific Light will already have been bound to this id via
3904  * bind_light().
3905  */
3906 void DXGraphicsStateGuardian9::
3907 enable_light(int light_id, bool enable) {
3908  HRESULT hr = _d3d_device->LightEnable(light_id, enable);
3909 
3910  if (FAILED(hr)) {
3911  wdxdisplay9_cat.warning()
3912  << "Could not enable light " << light_id << ": "
3913  << D3DERRORSTRING(hr) << "\n";
3914  }
3915 }
3916 
3917 /**
3918  * Intended to be overridden by a derived class to enable the indicated
3919  * clip_plane id. A specific PlaneNode will already have been bound to this
3920  * id via bind_clip_plane().
3921  */
3922 void DXGraphicsStateGuardian9::
3923 enable_clip_plane(int plane_id, bool enable) {
3924  if (enable) {
3925  _clip_plane_bits |= ((DWORD)1 << plane_id);
3926  } else {
3927  _clip_plane_bits &= ~((DWORD)1 << plane_id);
3928  }
3929  set_render_state(D3DRS_CLIPPLANEENABLE, _clip_plane_bits);
3930 }
3931 
3932 /**
3933  * Called the first time a particular clip_plane has been bound to a given id
3934  * within a frame, this should set up the associated hardware clip_plane with
3935  * the clip_plane's properties.
3936  */
3937 void DXGraphicsStateGuardian9::
3938 bind_clip_plane(const NodePath &plane, int plane_id) {
3939  // Get the plane in "world coordinates" (actually, view coordinates). This
3940  // means the plane in the coordinate space of the camera, converted to DX's
3941  // coordinate system.
3942  CPT(TransformState) transform = plane.get_transform(_scene_setup->get_camera_path());
3943  const LMatrix4 &plane_mat = transform->get_mat();
3944  LMatrix4 rel_mat = plane_mat * LMatrix4::convert_mat(CS_yup_left, CS_default);
3945  const PlaneNode *plane_node;
3946  DCAST_INTO_V(plane_node, plane.node());
3947  LPlanef world_plane = LCAST(float, plane_node->get_plane() * rel_mat);
3948 
3949  HRESULT hr = _d3d_device->SetClipPlane(plane_id, world_plane.get_data());
3950  if (FAILED(hr)) {
3951  wdxdisplay9_cat.warning()
3952  << "Could not set clip plane for " << plane
3953  << " to id " << plane_id << ": " << D3DERRORSTRING(hr) << "\n";
3954  }
3955 }
3956 
3957 /**
3958  * This is called by the associated GraphicsWindow when close_window() is
3959  * called. It should null out the _win pointer and possibly free any open
3960  * resources associated with the GSG.
3961  */
3962 void DXGraphicsStateGuardian9::
3963 close_gsg() {
3964  GraphicsStateGuardian::close_gsg();
3965 
3966  if (_prepared_objects.is_null()) {
3967  return;
3968  }
3969 
3970  if (dxgsg9_cat.is_debug()) {
3971  dxgsg9_cat.debug()
3972  << "Closing GSG, prepared_objects count = "
3973  << _prepared_objects->get_ref_count() << "\n";
3974  }
3975 
3976  // Unlike in OpenGL, in DX9 it is safe to try to explicitly release any
3977  // textures here. And it may even be a good idea.
3978  if (_prepared_objects->get_ref_count() == 1) {
3979  release_all();
3980 
3981  // Now we need to actually delete all of the objects we just released.
3982  Thread *current_thread = Thread::get_current_thread();
3983  _prepared_objects->begin_frame(this, current_thread);
3984  _prepared_objects->end_frame(current_thread);
3985  }
3986 }
3987 
3988 /**
3989  * Frees some memory that was explicitly allocated within the dxgsg.
3990  */
3991 void DXGraphicsStateGuardian9::
3992 free_nondx_resources() {
3993 #ifdef HAVE_CG
3994  if (_cg_context) {
3995  cgDestroyContext(_cg_context);
3996  _cg_context = 0;
3997  }
3998 #endif
3999 }
4000 
4001 /**
4002  * setup for re-calling dx_init(), this is not the final exit cleanup routine
4003  * (see dx_cleanup)
4004  */
4005 void DXGraphicsStateGuardian9::
4006 free_d3d_device() {
4007  // dont want a full reset of gsg, just a state clear
4008  _state_rs = RenderState::make_empty();
4009  _state_mask.clear();
4010 
4011  // want gsg to pass all state settings through
4012 
4013  _dx_is_ready = false;
4014 
4015  if (_d3d_device != nullptr) {
4016  for(int i = 0; i < D3D_MAXTEXTURESTAGES; i++) {
4017  // d3d should release this stuff internally anyway, but whatever
4018  _d3d_device->SetTexture(i, nullptr);
4019  }
4020  }
4021 
4022  release_all();
4023 
4024  if (_d3d_device != nullptr) {
4025  RELEASE(_d3d_device, dxgsg9, "d3dDevice", RELEASE_DOWN_TO_ZERO);
4026  }
4027 
4028  free_nondx_resources();
4029 
4030  // obviously we dont release ID3D9, just ID3DDevice9
4031 }
4032 
4033 /**
4034  * Sets up the glDrawBuffer to render into the buffer indicated by the
4035  * RenderBuffer object. This only sets up the color bits; it does not affect
4036  * the depth, stencil, accum layers.
4037  */
4038 void DXGraphicsStateGuardian9::
4039 set_draw_buffer(const RenderBuffer &rb) {
4040  dxgsg9_cat.fatal() << "DX set_draw_buffer unimplemented!!!";
4041  return;
4042 }
4043 
4044 /**
4045  * Vestigial analog of glReadBuffer
4046  */
4047 void DXGraphicsStateGuardian9::
4048 set_read_buffer(const RenderBuffer &rb) {
4049  if (rb._buffer_type & RenderBuffer::T_front) {
4050  _cur_read_pixel_buffer = RenderBuffer::T_front;
4051  } else if (rb._buffer_type & RenderBuffer::T_back) {
4052  _cur_read_pixel_buffer = RenderBuffer::T_back;
4053  } else if (rb._buffer_type & RenderBuffer::T_aux_rgba_ALL) {
4054  _cur_read_pixel_buffer = RenderBuffer::T_back;
4055  } else {
4056  dxgsg9_cat.error() << "Invalid or unimplemented Argument to set_read_buffer!\n";
4057  }
4058  return;
4059 }
4060 
4061 /**
4062  * Returns the array of four floats that should be issued as the light's
4063  * color, as scaled by the current value of _light_color_scale, in the case of
4064  * color_scale_via_lighting.
4065  */
4066 const D3DCOLORVALUE &DXGraphicsStateGuardian9::
4067 get_light_color(Light *light) const {
4068  LColor c = light->get_color();
4069  static LColorf cf;
4070  cf.set(c[0] * _light_color_scale[0],
4071  c[1] * _light_color_scale[1],
4072  c[2] * _light_color_scale[2],
4073  c[3] * _light_color_scale[3]);
4074  return *(D3DCOLORVALUE *)cf.get_data();
4075 }
4076 
4077 /**
4078  * Maps from ColorBlendAttrib::Mode to D3DBLENDOP vaule.
4079  */
4080 D3DBLENDOP DXGraphicsStateGuardian9::
4081 get_blend_mode(ColorBlendAttrib::Mode mode) {
4082  switch (mode) {
4083  case ColorBlendAttrib::M_add:
4084  return D3DBLENDOP_ADD;
4085 
4086  case ColorBlendAttrib::M_subtract:
4087  return D3DBLENDOP_SUBTRACT;
4088 
4089  case ColorBlendAttrib::M_inv_subtract:
4090  return D3DBLENDOP_REVSUBTRACT;
4091 
4092  case ColorBlendAttrib::M_min:
4093  return D3DBLENDOP_MIN;
4094 
4095  case ColorBlendAttrib::M_max:
4096  return D3DBLENDOP_MAX;
4097  }
4098 
4099  dxgsg9_cat.error()
4100  << "Unknown color blend mode " << (int)mode << endl;
4101  return D3DBLENDOP_ADD;
4102 }
4103 
4104 /**
4105  * Maps from ColorBlendAttrib::Operand to D3DBLEND value.
4106  */
4107 D3DBLEND DXGraphicsStateGuardian9::
4108 get_blend_func(ColorBlendAttrib::Operand operand) {
4109  switch (operand) {
4110  case ColorBlendAttrib::O_zero:
4111  return D3DBLEND_ZERO;
4112 
4113  case ColorBlendAttrib::O_one:
4114  return D3DBLEND_ONE;
4115 
4116  case ColorBlendAttrib::O_incoming_color:
4117  return D3DBLEND_SRCCOLOR;
4118 
4119  case ColorBlendAttrib::O_one_minus_incoming_color:
4120  return D3DBLEND_INVSRCCOLOR;
4121 
4122  case ColorBlendAttrib::O_fbuffer_color:
4123  return D3DBLEND_DESTCOLOR;
4124 
4125  case ColorBlendAttrib::O_one_minus_fbuffer_color:
4126  return D3DBLEND_INVDESTCOLOR;
4127 
4128  case ColorBlendAttrib::O_incoming_alpha:
4129  return D3DBLEND_SRCALPHA;
4130 
4131  case ColorBlendAttrib::O_one_minus_incoming_alpha:
4132  return D3DBLEND_INVSRCALPHA;
4133 
4134  case ColorBlendAttrib::O_fbuffer_alpha:
4135  return D3DBLEND_DESTALPHA;
4136 
4137  case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
4138  return D3DBLEND_INVDESTALPHA;
4139 
4140  case ColorBlendAttrib::O_constant_color:
4141  // Not supported by DX.
4142  return D3DBLEND_SRCCOLOR;
4143 
4144  case ColorBlendAttrib::O_one_minus_constant_color:
4145  // Not supported by DX.
4146  return D3DBLEND_INVSRCCOLOR;
4147 
4148  case ColorBlendAttrib::O_constant_alpha:
4149  // Not supported by DX.
4150  return D3DBLEND_SRCALPHA;
4151 
4152  case ColorBlendAttrib::O_one_minus_constant_alpha:
4153  // Not supported by DX.
4154  return D3DBLEND_INVSRCALPHA;
4155 
4156  case ColorBlendAttrib::O_incoming_color_saturate:
4157  return D3DBLEND_SRCALPHASAT;
4158 
4159  case ColorBlendAttrib::O_incoming1_color:
4160  return (D3DBLEND)16; //D3DBLEND_SRCCOLOR2;
4161 
4162  case ColorBlendAttrib::O_one_minus_incoming1_color:
4163  return (D3DBLEND)17; //D3DBLEND_INVSRCCOLOR2;
4164 
4165  case ColorBlendAttrib::O_incoming1_alpha:
4166  // Not supported by DX9.
4167  return (D3DBLEND)18;
4168 
4169  case ColorBlendAttrib::O_one_minus_incoming1_alpha:
4170  // Not supported by DX9.
4171  return (D3DBLEND)19;
4172  }
4173 
4174  dxgsg9_cat.error()
4175  << "Unknown color blend operand " << (int)operand << endl;
4176  return D3DBLEND_ZERO;
4177 }
4178 
4179 /**
4180  * Reports the DX texture manager's activity to PStats.
4181  */
4182 void DXGraphicsStateGuardian9::
4183 report_texmgr_stats() {
4184 
4185 #ifdef DO_PSTATS
4186  HRESULT hr;
4187  hr = 0;
4188 
4189 #ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM
4190  DWORD dwTexTotal, dwTexFree, dwVidTotal, dwVidFree;
4191 
4192  if (_total_texmem_pcollector.is_active()) {
4193  DDSCAPS2 ddsCaps;
4194 
4195  ZeroMemory(&ddsCaps, sizeof(ddsCaps));
4196 
4197  ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
4198  if (FAILED( hr = _d3d_device->GetAvailableVidMem(&ddsCaps, &dwVidTotal, &dwVidFree))) {
4199  dxgsg9_cat.fatal() << "report_texmgr GetAvailableVidMem for VIDMEM failed : result = " << D3DERRORSTRING(hr);
4200  throw_event("panda3d-render-error");
4201  return;
4202  }
4203 
4204  ddsCaps.dwCaps = DDSCAPS_TEXTURE;
4205  if (FAILED( hr = _d3d_device->GetAvailableVidMem(&ddsCaps, &dwTexTotal, &dwTexFree))) {
4206  dxgsg9_cat.fatal() << "report_texmgr GetAvailableVidMem for TEXTURE failed : result = " << D3DERRORSTRING(hr);
4207  throw_event("panda3d-render-error");
4208  return;
4209  }
4210  }
4211 #endif // TEXMGRSTATS_USES_GETAVAILVIDMEM
4212 
4213  D3DDEVINFO_RESOURCEMANAGER all_resource_stats;
4214  ZeroMemory(&all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER));
4215 
4216 /* ***** DX9, GetInfo ( ) NOT IN DX9 */
4217 /*
4218  if (!_tex_stats_retrieval_impossible) {
4219  hr = _d3d_device->GetInfo(D3DDEVINFOID_RESOURCEMANAGER, &all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER));
4220  if (hr != D3D_OK) {
4221  if (hr == S_FALSE) {
4222  static int PrintedMsg = 2;
4223  if (PrintedMsg>0) {
4224  if (dxgsg9_cat.is_debug()) {
4225  dxgsg9_cat.debug()
4226  << "texstats GetInfo() requires debug DX DLLs to be installed!!\n";
4227  }
4228  ZeroMemory(&all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER));
4229  _tex_stats_retrieval_impossible = true;
4230  }
4231  } else {
4232  dxgsg9_cat.error() << "GetInfo(RESOURCEMANAGER) failed to get tex stats: result = " << D3DERRORSTRING(hr);
4233  return;
4234  }
4235  }
4236  }
4237 */
4238 
4239  // Tell PStats about the state of the texture memory.
4240 
4241  if (_texmgrmem_total_pcollector.is_active()) {
4242  // report zero if no debug dlls, to signal this info is invalid
4243  _texmgrmem_total_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].TotalBytes);
4244  _texmgrmem_resident_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].WorkingSetBytes);
4245  }
4246 #ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM
4247  if (_total_texmem_pcollector.is_active()) {
4248  _total_texmem_pcollector.set_level(dwTexTotal);
4249  _used_texmem_pcollector.set_level(dwTexTotal - dwTexFree);
4250  }
4251 #endif // TEXMGRSTATS_USES_GETAVAILVIDMEM
4252 #endif // DO_PSTATS
4253 }
4254 
4255 /**
4256  *
4257  */
4258 void DXGraphicsStateGuardian9::
4259 set_context(DXScreenData *new_context) {
4260  nassertv(new_context != nullptr);
4261  _screen = new_context;
4262  _d3d_device = _screen->_d3d_device; //copy this one field for speed of deref
4263  _swap_chain = _screen->_swap_chain; //copy this one field for speed of deref
4264 
4265  _screen->_dxgsg9 = this;
4266  set_cg_device(_d3d_device);
4267 }
4268 
4269 /**
4270  * Set render target to the backbuffer of current swap chain.
4271  */
4272 void DXGraphicsStateGuardian9::
4273 set_render_target() {
4274  if (_d3d_device == nullptr) {
4275  return;
4276  }
4277 
4278  LPDIRECT3DSURFACE9 back = nullptr, stencil = nullptr;
4279 
4280  UINT swap_chain;
4281 
4282  /* ***** DX9 swap_chain ??? */
4283  swap_chain = 0;
4284 
4285  if (!_swap_chain) //maybe fullscreen mode or main/single window
4286  _d3d_device->GetBackBuffer(swap_chain, 0, D3DBACKBUFFER_TYPE_MONO, &back);
4287  else
4288  _swap_chain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &back);
4289 
4290  // wdxdisplay9_cat.debug() << "swapchain is " << _swap_chain << "\n";
4291  // wdxdisplay9_cat.debug() << "back buffer is " << back << "\n";
4292 
4293  _d3d_device->GetDepthStencilSurface(&stencil);
4294 
4295 // _d3d_device->SetRenderTarget(back, stencil);
4296  DWORD render_target_index;
4297  render_target_index = 0;
4298  _d3d_device->SetRenderTarget(render_target_index, back);
4299 
4300  if (back) {
4301  back->Release();
4302  }
4303  if (stencil) {
4304  stencil->Release();
4305  }
4306 }
4307 
4308 /**
4309  *
4310  */
4311 void DXGraphicsStateGuardian9::
4312 set_texture_blend_mode(int i, const TextureStage *stage) {
4313  switch (stage->get_mode()) {
4314  case TextureStage::M_modulate:
4315  case TextureStage::M_modulate_glow:
4316  case TextureStage::M_modulate_gloss:
4317  // emulates GL_MODULATE glTexEnv mode
4318  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_MODULATE);
4319  set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
4320  set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
4321  set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
4322  set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
4323  set_texture_stage_state(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
4324  break;
4325 
4326  case TextureStage::M_decal:
4327  // emulates GL_DECAL glTexEnv mode
4328  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA);
4329  set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
4330  set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
4331 
4332  set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
4333  set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
4334  break;
4335 
4336  case TextureStage::M_replace:
4337  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
4338  set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
4339 
4340  set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
4341  set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
4342  break;
4343 
4344  case TextureStage::M_add:
4345  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_ADD);
4346  set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
4347  set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
4348 
4349  set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
4350  set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
4351  set_texture_stage_state(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
4352  break;
4353 
4354  case TextureStage::M_blend:
4355  case TextureStage::M_blend_color_scale:
4356  {
4357  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_LERP);
4358  set_texture_stage_state(i, D3DTSS_COLORARG0, D3DTA_TEXTURE);
4359  set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
4360  set_texture_stage_state(i, D3DTSS_COLORARG1, _constant_color_operand);
4361 
4362  set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
4363  set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
4364  set_texture_stage_state(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
4365  }
4366  break;
4367 
4368  case TextureStage::M_combine:
4369  // M_combine mode begins a collection of more sophisticated modes, which
4370  // match up more closely with DirectX's built-in modes.
4372  (i, D3DTSS_COLOROP,
4373  get_texture_operation(stage->get_combine_rgb_mode(),
4374  stage->get_rgb_scale()));
4375 
4376  switch (stage->get_num_combine_rgb_operands()) {
4377  case 3:
4379  (i, D3DTSS_COLORARG0,
4380  get_texture_argument(stage->get_combine_rgb_source2(),
4381  stage->get_combine_rgb_operand2()));
4382  // fall through
4383 
4384  case 2:
4386  (i, D3DTSS_COLORARG2,
4387  get_texture_argument(stage->get_combine_rgb_source1(),
4388  stage->get_combine_rgb_operand1()));
4389  // fall through
4390 
4391  case 1:
4393  (i, D3DTSS_COLORARG1,
4394  get_texture_argument(stage->get_combine_rgb_source0(),
4395  stage->get_combine_rgb_operand0()));
4396  // fall through
4397 
4398  default:
4399  break;
4400  }
4401 
4403  (i, D3DTSS_ALPHAOP,
4404  get_texture_operation(stage->get_combine_alpha_mode(),
4405  stage->get_alpha_scale()));
4406 
4407  switch (stage->get_num_combine_alpha_operands()) {
4408  case 3:
4410  (i, D3DTSS_ALPHAARG0,
4411  get_texture_argument(stage->get_combine_alpha_source2(),
4412  stage->get_combine_alpha_operand2()));
4413  // fall through
4414 
4415  case 2:
4417  (i, D3DTSS_ALPHAARG2,
4418  get_texture_argument(stage->get_combine_alpha_source1(),
4419  stage->get_combine_alpha_operand1()));
4420  // fall through
4421 
4422  case 1:
4424  (i, D3DTSS_ALPHAARG1,
4425  get_texture_argument(stage->get_combine_alpha_source0(),
4426  stage->get_combine_alpha_operand0()));
4427  // fall through
4428 
4429  default:
4430  break;
4431  }
4432  break;
4433 
4434  default:
4435  dxgsg9_cat.error()
4436  << "Unknown texture mode " << (int)stage->get_mode() << endl;
4437  break;
4438  }
4439 
4440  if (stage->get_saved_result()) {
4441  set_texture_stage_state(i, D3DTSS_RESULTARG, D3DTA_TEMP);
4442  } else {
4443  set_texture_stage_state(i, D3DTSS_RESULTARG, D3DTA_CURRENT);
4444  }
4445 
4446  if (stage->uses_color() || stage->involves_color_scale()) {
4447  // Set up the constant color for this stage.
4448 
4449  D3DCOLOR constant_color;
4450  if (stage->involves_color_scale() && _color_scale_enabled) {
4451  LColor color = stage->get_color();
4452  color.set(color[0] * _current_color_scale[0],
4453  color[1] * _current_color_scale[1],
4454  color[2] * _current_color_scale[2],
4455  color[3] * _current_color_scale[3]);
4456  _texture_involves_color_scale = true;
4457  constant_color = LColor_to_D3DCOLOR(color);
4458  } else {
4459  constant_color = LColor_to_D3DCOLOR(stage->get_color());
4460  }
4461  if (_supports_texture_constant_color) {
4462  set_texture_stage_state(i, D3DTSS_CONSTANT, constant_color);
4463  } else {
4464  // This device doesn't supoprt a per-stage constant color, so we have to
4465  // fall back to a single constant color for the overall texture
4466  // pipeline.
4467  set_render_state(D3DRS_TEXTUREFACTOR, constant_color);
4468  }
4469  }
4470 }
4471 
4472 /**
4473  * Clean up the DirectX environment, accounting for exit()
4474  */
4475 void DXGraphicsStateGuardian9::
4476 dx_cleanup() {
4477  if (!_d3d_device) {
4478  return;
4479  }
4480 
4481  free_nondx_resources();
4482  PRINT_REFCNT(dxgsg9, _d3d_device);
4483 
4484  // Do a safe check for releasing the D3DDEVICE. RefCount should be zero. if
4485  // we're called from exit(), _d3d_device may already have been released
4486  RELEASE(_d3d_device, dxgsg9, "d3dDevice", RELEASE_DOWN_TO_ZERO);
4487  _screen->_d3d_device = nullptr;
4488 
4489  // Releasing pD3D is now the responsibility of the GraphicsPipe destructor
4490 }
4491 
4492 /**
4493  * This function checks current device's framebuffer dimension against passed
4494  * p_presentation_params backbuffer dimension to determine a device reset if
4495  * there is only one window or it is the main window or fullscreen mode then,
4496  * it resets the device. Finally it returns the new DXScreenData through
4497  * parameter screen
4498  */
4499 HRESULT DXGraphicsStateGuardian9::
4500 reset_d3d_device(D3DPRESENT_PARAMETERS *presentation_params,
4501  DXScreenData **screen) {
4502  HRESULT hr;
4503 
4504  nassertr(IS_VALID_PTR(presentation_params), E_FAIL);
4505  nassertr(IS_VALID_PTR(_screen->_d3d9), E_FAIL);
4506  nassertr(IS_VALID_PTR(_d3d_device), E_FAIL);
4507 
4508  // for windowed mode make sure our format matches the desktop fmt, in case
4509  // the desktop mode has been changed
4510  _screen->_d3d9->GetAdapterDisplayMode(_screen->_card_id, &_screen->_display_mode);
4511  presentation_params->BackBufferFormat = _screen->_display_mode.Format;
4512 
4513  // here we have to look at the _presentation_reset frame buffer dimension if
4514  // current window's dimension is bigger than _presentation_reset we have to
4515  // reset the device before creating new swapchain. inorder to reset
4516  // properly, we need to release all swapchains
4517 
4518  if (true || !(_screen->_swap_chain)
4519  || (_presentation_reset.BackBufferWidth < presentation_params->BackBufferWidth)
4520  || (_presentation_reset.BackBufferHeight < presentation_params->BackBufferHeight)) {
4521  if (wdxdisplay9_cat.is_debug()) {
4522  wdxdisplay9_cat.debug()
4523  << "swap_chain = " << _screen->_swap_chain << " _presentation_reset = "
4524  << _presentation_reset.BackBufferWidth << "x" << _presentation_reset.BackBufferHeight
4525  << " presentation_params = "
4526  << presentation_params->BackBufferWidth << "x" << presentation_params->BackBufferHeight << "\n";
4527  }
4528 
4529  get_engine()->reset_all_windows(false);// reset old swapchain by releasing
4530 
4531  if (_screen->_swap_chain) { //other windows might be using bigger buffers
4532  _presentation_reset.BackBufferWidth = max(_presentation_reset.BackBufferWidth, presentation_params->BackBufferWidth);
4533  _presentation_reset.BackBufferHeight = max(_presentation_reset.BackBufferHeight, presentation_params->BackBufferHeight);
4534 
4535  } else { // single window, must reset to the new presentation_params dimension
4536  _presentation_reset.BackBufferWidth = presentation_params->BackBufferWidth;
4537  _presentation_reset.BackBufferHeight = presentation_params->BackBufferHeight;
4538  }
4539 
4540  // Calling this forces all of the textures and vbuffers to be regenerated,
4541  // a prerequisite to calling Reset().
4542  release_all();
4543 
4544  // Just to be extra-conservative for now, we'll go ahead and release the
4545  // vbuffers and ibuffers at least; they're relatively cheap to replace.
4548 
4549  if (_white_vbuffer != nullptr) {
4550  _white_vbuffer->Release();
4551  _white_vbuffer = nullptr;
4552  }
4553 
4554  // must be called before reset
4555  Thread *current_thread = Thread::get_current_thread();
4556  _prepared_objects->begin_frame(this, current_thread);
4557 
4558  // release graphics buffer surfaces
4559  {
4560  wdxGraphicsBuffer9 *graphics_buffer;
4561  std::list <wdxGraphicsBuffer9 **>::iterator graphics_buffer_iterator;
4562 
4563  for (graphics_buffer_iterator = _graphics_buffer_list.begin( ); graphics_buffer_iterator != _graphics_buffer_list.end( ); graphics_buffer_iterator++)
4564  {
4565  graphics_buffer = **graphics_buffer_iterator;
4566  if (graphics_buffer -> _color_backing_store)
4567  {
4568  graphics_buffer -> _color_backing_store -> Release ( );
4569  graphics_buffer -> _color_backing_store = 0;
4570  }
4571  if (graphics_buffer -> _depth_backing_store)
4572  {
4573  graphics_buffer -> _depth_backing_store -> Release ( );
4574  graphics_buffer -> _depth_backing_store = 0;
4575  }
4576  }
4577  }
4578 
4579  mark_new();
4580  hr = _d3d_device->Reset(&_presentation_reset);
4581  if (FAILED(hr) && hr != D3DERR_DEVICELOST) {
4582  return hr;
4583  }
4584 
4585  get_engine()->reset_all_windows(true);// reset with new swapchains by creating
4586  if (screen) {
4587  *screen = nullptr;
4588  }
4589 
4590  if (presentation_params != &_screen->_presentation_params) {
4591  memcpy(&_screen->_presentation_params, presentation_params, sizeof(D3DPRESENT_PARAMETERS));
4592  }
4593 
4594  return hr;
4595  }
4596 
4597  // release the old swapchain and create a new one
4598  if (_screen && _screen->_swap_chain) {
4599  _screen->_swap_chain->Release();
4600  wdxdisplay9_cat.debug()
4601  << "swap chain " << _screen->_swap_chain << " is released\n";
4602  _screen->_swap_chain = nullptr;
4603  hr = _d3d_device->CreateAdditionalSwapChain(presentation_params, &_screen->_swap_chain);
4604  }
4605  if (SUCCEEDED(hr)) {
4606  if (presentation_params != &_screen->_presentation_params) {
4607  memcpy(&_screen->_presentation_params, presentation_params, sizeof(D3DPRESENT_PARAMETERS));
4608  }
4609  if (screen) {
4610  *screen = _screen;
4611  }
4612  }
4613  return hr;
4614 }
4615 
4616 /**
4617  *
4618  */
4619 bool DXGraphicsStateGuardian9::
4620 check_cooperative_level() {
4621  bool bDoReactivateWindow = false;
4622  if (_d3d_device == nullptr) {
4623  return false;
4624  }
4625 
4626  HRESULT hr = _d3d_device->TestCooperativeLevel();
4627 
4628  if (SUCCEEDED(hr)) {
4629  nassertr(SUCCEEDED(_last_testcooplevel_result), false);
4630  return true;
4631  }
4632 
4633  switch (hr) {
4634  case D3DERR_DEVICENOTRESET:
4635  _dx_is_ready = false;
4636 
4637  // call this just in case
4638  _prepared_objects->begin_frame(this, Thread::get_current_thread());
4639 
4640  hr = reset_d3d_device(&_screen->_presentation_params);
4641  if (FAILED(hr)) {
4642  // I think this shouldnt fail unless I've screwed up the
4643  // _presentation_params from the original working ones somehow
4644  dxgsg9_cat.error()
4645  << "check_cooperative_level Reset() failed, hr = " << D3DERRORSTRING(hr);
4646  }
4647 
4648  hr = _d3d_device->TestCooperativeLevel();
4649  if (FAILED(hr)) {
4650  // internal chk, shouldnt fail
4651  dxgsg9_cat.error()
4652  << "TestCooperativeLevel following Reset() failed, hr = " << D3DERRORSTRING(hr);
4653 
4654  }
4655 
4656  _dx_is_ready = TRUE;
4657  break;
4658 
4659  case D3DERR_DEVICELOST:
4660  // sleep while the device is lost to free up the CPU
4661  Sleep (10);
4662 
4663  if (SUCCEEDED(_last_testcooplevel_result)) {
4664  if (_dx_is_ready) {
4665  _dx_is_ready = false;
4666  if (dxgsg9_cat.is_debug()) {
4667  dxgsg9_cat.debug() << "D3D Device was Lost, waiting...\n";
4668  }
4669  }
4670  }
4671  }
4672 
4673  _last_testcooplevel_result = hr;
4674  return SUCCEEDED(hr);
4675 }
4676 
4677 /**
4678  * redraw primary buffer
4679  */
4680 void DXGraphicsStateGuardian9::
4681 show_frame() {
4682  if (_d3d_device == nullptr) {
4683  return;
4684  }
4685 
4686  HRESULT hr;
4687 
4688  if (_swap_chain) {
4689  DWORD flags;
4690  flags = 0;
4691 
4692  hr = _swap_chain->Present(nullptr, nullptr, (HWND)nullptr, nullptr, flags);
4693  } else {
4694  hr = _d3d_device->Present(nullptr, nullptr, (HWND)nullptr, nullptr);
4695  }
4696 
4697  if (FAILED(hr)) {
4698  if (hr == D3DERR_DEVICELOST) {
4699  check_cooperative_level();
4700  } else {
4701  dxgsg9_cat.error()
4702  << "show_frame() - Present() failed" << D3DERRORSTRING(hr);
4703  throw_event("panda3d-render-error");
4704  }
4705  }
4706 }
4707 
4708 /**
4709  *
4710  */
4711 bool DXGraphicsStateGuardian9::
4712 create_swap_chain(DXScreenData *new_context) {
4713  // Instead of creating a device and rendering as d3ddevice->present() we
4714  // should render using SwapChain->present(). This is done to support
4715  // multiple windows rendering. For that purpose, we need to set additional
4716  // swap chains here.
4717 
4718  HRESULT hr;
4719  hr = new_context->_d3d_device->CreateAdditionalSwapChain(&new_context->_presentation_params, &new_context->_swap_chain);
4720  if (FAILED(hr)) {
4721  wdxdisplay9_cat.debug() << "Swapchain creation failed :"<<D3DERRORSTRING(hr)<<"\n";
4722  return false;
4723  }
4724  return true;
4725 }
4726 
4727 /**
4728  * Release the swap chain on this DXScreenData
4729  */
4730 bool DXGraphicsStateGuardian9::
4731 release_swap_chain(DXScreenData *new_context) {
4732  HRESULT hr;
4733  if (new_context->_swap_chain) {
4734  hr = new_context->_swap_chain->Release();
4735  if (FAILED(hr)) {
4736  wdxdisplay9_cat.debug() << "Swapchain release failed:" << D3DERRORSTRING(hr) << "\n";
4737  return false;
4738  }
4739  }
4740  return true;
4741 }
4742 
4743 /**
4744  * copies the PresReset from passed DXScreenData
4745  */
4746 void DXGraphicsStateGuardian9::
4747 copy_pres_reset(DXScreenData *screen) {
4748  memcpy(&_presentation_reset, &_screen->_presentation_params, sizeof(D3DPRESENT_PARAMETERS));
4749 }
4750 
4751 /**
4752  *
4753  */
4754 D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian9::
4755 get_d3d_min_type(SamplerState::FilterType filter_type) {
4756  switch (filter_type) {
4757  case SamplerState::FT_nearest:
4758  return D3DTEXF_POINT;
4759 
4760  case SamplerState::FT_linear:
4761  return D3DTEXF_LINEAR;
4762 
4763  case SamplerState::FT_nearest_mipmap_nearest:
4764  return D3DTEXF_POINT;
4765 
4766  case SamplerState::FT_linear_mipmap_nearest:
4767  return D3DTEXF_LINEAR;
4768 
4769  case SamplerState::FT_nearest_mipmap_linear:
4770  return D3DTEXF_POINT;
4771 
4772  case SamplerState::FT_linear_mipmap_linear:
4773  return D3DTEXF_LINEAR;
4774 
4775  case SamplerState::FT_shadow:
4776  case SamplerState::FT_default:
4777  return D3DTEXF_LINEAR;
4778  }
4779 
4780  dxgsg9_cat.error()
4781  << "Invalid FilterType value (" << (int)filter_type << ")\n";
4782  return D3DTEXF_POINT;
4783 }
4784 
4785 /**
4786  *
4787  */
4788 D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian9::
4789 get_d3d_mip_type(SamplerState::FilterType filter_type) {
4790  switch (filter_type) {
4791  case SamplerState::FT_nearest:
4792  return D3DTEXF_NONE;
4793 
4794  case SamplerState::FT_linear:
4795  return D3DTEXF_NONE;
4796 
4797  case SamplerState::FT_nearest_mipmap_nearest:
4798  return D3DTEXF_POINT;
4799 
4800  case SamplerState::FT_linear_mipmap_nearest:
4801  return D3DTEXF_POINT;
4802 
4803  case SamplerState::FT_nearest_mipmap_linear:
4804  return D3DTEXF_LINEAR;
4805 
4806  case SamplerState::FT_linear_mipmap_linear:
4807  return D3DTEXF_LINEAR;
4808 
4809  case SamplerState::FT_shadow:
4810  case SamplerState::FT_default:
4811  return D3DTEXF_NONE;
4812  }
4813 
4814  dxgsg9_cat.error()
4815  << "Invalid FilterType value (" << (int)filter_type << ")\n";
4816  return D3DTEXF_NONE;
4817 }
4818 
4819 /**
4820  * Returns the D3DTEXTUREOP value corresponding to the indicated
4821  * TextureStage::CombineMode enumerated type.
4822  */
4823 D3DTEXTUREOP DXGraphicsStateGuardian9::
4824 get_texture_operation(TextureStage::CombineMode mode, int scale) {
4825  switch (mode) {
4826  case TextureStage::CM_undefined:
4827  case TextureStage::CM_replace:
4828  return D3DTOP_SELECTARG1;
4829 
4830  case TextureStage::CM_modulate:
4831  if (scale < 2) {
4832  return D3DTOP_MODULATE;
4833  } else if (scale < 4) {
4834  return D3DTOP_MODULATE2X;
4835  } else {
4836  return D3DTOP_MODULATE4X;
4837  }
4838 
4839  case TextureStage::CM_add:
4840  return D3DTOP_ADD;
4841 
4842  case TextureStage::CM_add_signed:
4843  if (scale < 2) {
4844  return D3DTOP_ADDSIGNED;
4845  } else {
4846  return D3DTOP_ADDSIGNED2X;
4847  }
4848 
4849  case TextureStage::CM_interpolate:
4850  return D3DTOP_LERP;
4851 
4852  case TextureStage::CM_subtract:
4853  return D3DTOP_SUBTRACT;
4854 
4855  case TextureStage::CM_dot3_rgb:
4856  case TextureStage::CM_dot3_rgba:
4857  return D3DTOP_DOTPRODUCT3;
4858  }
4859 
4860  dxgsg9_cat.error()
4861  << "Invalid TextureStage::CombineMode value (" << (int)mode << ")\n";
4862  return D3DTOP_DISABLE;
4863 }
4864 
4865 /**
4866  * Returns the D3DTA value corresponding to the indicated
4867  * TextureStage::CombineSource and TextureStage::CombineOperand enumerated
4868  * types.
4869  */
4870 DWORD DXGraphicsStateGuardian9::
4871 get_texture_argument(TextureStage::CombineSource source,
4872  TextureStage::CombineOperand operand) const {
4873  switch (source) {
4874  case TextureStage::CS_undefined:
4875  case TextureStage::CS_texture:
4876  return D3DTA_TEXTURE | get_texture_argument_modifier(operand);
4877 
4878  case TextureStage::CS_constant:
4879  case TextureStage::CS_constant_color_scale:
4880  return _constant_color_operand | get_texture_argument_modifier(operand);
4881 
4882  case TextureStage::CS_primary_color:
4883  return D3DTA_DIFFUSE | get_texture_argument_modifier(operand);
4884 
4885  case TextureStage::CS_previous:
4886  return D3DTA_CURRENT | get_texture_argument_modifier(operand);
4887 
4888  case TextureStage::CS_last_saved_result:
4889  return D3DTA_TEMP | get_texture_argument_modifier(operand);
4890  }
4891  dxgsg9_cat.error()
4892  << "Invalid TextureStage::CombineSource value (" << (int)source << ")\n";
4893  return D3DTA_CURRENT;
4894 }
4895 
4896 /**
4897  * Returns the extra bits that modify the D3DTA argument, according to the
4898  * indicated TextureStage::CombineOperand enumerated type.
4899  */
4900 DWORD DXGraphicsStateGuardian9::
4901 get_texture_argument_modifier(TextureStage::CombineOperand operand) {
4902  switch (operand) {
4903  case TextureStage::CO_src_color:
4904  return 0;
4905 
4906  case TextureStage::CO_one_minus_src_color:
4907  return D3DTA_COMPLEMENT;
4908 
4909  case TextureStage::CO_src_alpha:
4910  return D3DTA_ALPHAREPLICATE;
4911 
4912  case TextureStage::CO_one_minus_src_alpha:
4913  return D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT;
4914 
4915  case TextureStage::CO_undefined:
4916  break;
4917  }
4918  dxgsg9_cat.error()
4919  << "Invalid TextureStage::CombineOperand value (" << (int)operand << ")\n";
4920  return 0;
4921 }
4922 
4923 /**
4924  * Issues the DrawPrimitiveUP call to draw the indicated primitive_type from
4925  * the given buffer. We add the num_vertices parameter, so we can determine
4926  * the size of the buffer.
4927  */
4928 void DXGraphicsStateGuardian9::
4929 draw_primitive_up(D3DPRIMITIVETYPE primitive_type,
4930  unsigned int primitive_count,
4931  unsigned int first_vertex,
4932  unsigned int num_vertices,
4933  const unsigned char *buffer, size_t stride) {
4934 
4935  // It appears that the common ATI driver seems to fail to draw anything in
4936  // the DrawPrimitiveUP() call if the address range of the buffer supplied
4937  // crosses over a multiple of 0x10000. That's incredibly broken, yet it
4938  // undeniably appears to be true. We'll have to hack around it.
4939 
4940  const unsigned char *buffer_start = buffer + stride * first_vertex;
4941  const unsigned char *buffer_end = buffer_start + stride * num_vertices;
4942 
4943  if (buffer_end - buffer_start > 0x10000) {
4944  // Actually, the buffer doesn't fit within the required limit anyway. Go
4945  // ahead and draw it and hope for the best.
4946  _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count,
4947  buffer_start, stride);
4948 
4949  } else if ((((uintptr_t)buffer_end ^ (uintptr_t)buffer_start) & ~0xffff) == 0) {
4950  // No problem; we can draw the buffer directly.
4951  _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count,
4952  buffer_start, stride);
4953 
4954  } else {
4955  // We have a problem--the buffer crosses over a 0x10000 boundary. We have
4956  // to copy the buffer to a temporary buffer that we can draw from.
4957  unsigned char *safe_buffer_start = get_safe_buffer_start();
4958  memcpy(safe_buffer_start, buffer_start, buffer_end - buffer_start);
4959  _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count,
4960  safe_buffer_start, stride);
4961 
4962  }
4963 }
4964 
4965 /**
4966  * Issues the DrawIndexedPrimitiveUP call to draw the indicated primitive_type
4967  * from the given buffer. As in draw_primitive_up(), above, the parameter
4968  * list is not exactly one-for-one with the DrawIndexedPrimitiveUP() call, but
4969  * it's similar (in particular, we pass max_index instead of NumVertices,
4970  * which always seemed ambiguous to me).
4971  */
4972 void DXGraphicsStateGuardian9::
4973 draw_indexed_primitive_up(D3DPRIMITIVETYPE primitive_type,
4974  unsigned int min_index, unsigned int max_index,
4975  unsigned int num_primitives,
4976  const unsigned char *index_data,
4977  D3DFORMAT index_type,
4978  const unsigned char *buffer, size_t stride) {
4979  // As above, we'll hack the case of the buffer crossing the 0x10000
4980  // boundary.
4981  const unsigned char *buffer_start = buffer + stride * min_index;
4982  const unsigned char *buffer_end = buffer + stride * (max_index + 1);
4983 
4984  if (buffer_end - buffer_start > 0x10000) {
4985  // Actually, the buffer doesn't fit within the required limit anyway. Go
4986  // ahead and draw it and hope for the best.
4987  _d3d_device->DrawIndexedPrimitiveUP
4988  (primitive_type, min_index, max_index - min_index + 1, num_primitives,
4989  index_data, index_type, buffer, stride);
4990 
4991  } else if ((((uintptr_t)buffer_end ^ (uintptr_t)buffer_start) & ~0xffff) == 0) {
4992  // No problem; we can draw the buffer directly.
4993  _d3d_device->DrawIndexedPrimitiveUP
4994  (primitive_type, min_index, max_index - min_index + 1, num_primitives,
4995  index_data, index_type, buffer, stride);
4996 
4997  } else {
4998  // We have a problem--the buffer crosses over a 0x10000 boundary. We have
4999  // to copy the buffer to a temporary buffer that we can draw from.
5000  unsigned char *safe_buffer_start = get_safe_buffer_start();
5001  memcpy(safe_buffer_start, buffer_start, buffer_end - buffer_start);
5002  _d3d_device->DrawIndexedPrimitiveUP
5003  (primitive_type, min_index, max_index - min_index + 1, num_primitives,
5004  index_data, index_type, safe_buffer_start - stride * min_index, stride);
5005  }
5006 }
5007 
5008 /**
5009  * This function is called after the creation of textures, vertex buffers, and
5010  * index buffers to check if DirectX is out of memory. If DirectX is out of
5011  * memory and the LRU is being used, then page out some memory. This function
5012  * is a fail-safe just in case another process allocates video memory, DirectX
5013  * is fragmented, or there are some borderline memory allocation cases, ...
5014  */
5016 check_dx_allocation (HRESULT result, int allocation_size, int attempts)
5017 {
5018  bool retry;
5019 
5020  retry = false;
5021  if (attempts <= 4)
5022  {
5023  switch (result) {
5024  case D3D_OK:
5025  break;
5026 
5027  case D3DERR_OUTOFVIDEOMEMORY:
5028  case E_OUTOFMEMORY:
5029  // increase the page out size as the number of attempts increases
5030  {
5031  size_t current_size = _prepared_objects->_graphics_memory_lru.get_total_size();
5032  size_t target_size = max(current_size - allocation_size * attempts, (size_t) 0);
5033  _prepared_objects->_graphics_memory_lru.evict_to(target_size);
5034  dxgsg9_cat.info()
5035  << "Evicted " << current_size - _prepared_objects->_graphics_memory_lru.get_total_size() << " bytes of texture memory to make room for more.\n";
5036  if (_prepared_objects->_graphics_memory_lru.get_total_size() < current_size) {
5037  retry = true;
5038  }
5039  }
5040  break;
5041 
5042  default:
5043  break;
5044  }
5045  }
5046 
5047  return retry;
5048 }
5049 
5050 // DX stencil code section
5051 static int dx_stencil_comparison_function_array[] = {
5052  D3DCMP_NEVER,
5053  D3DCMP_LESS,
5054  D3DCMP_EQUAL,
5055  D3DCMP_LESSEQUAL,
5056  D3DCMP_GREATER,
5057  D3DCMP_NOTEQUAL,
5058  D3DCMP_GREATEREQUAL,
5059  D3DCMP_ALWAYS,
5060 };
5061 
5062 static int dx_stencil_operation_array[] = {
5063  D3DSTENCILOP_KEEP,
5064  D3DSTENCILOP_ZERO,
5065  D3DSTENCILOP_REPLACE,
5066  D3DSTENCILOP_INCR,
5067  D3DSTENCILOP_DECR,
5068  D3DSTENCILOP_INVERT,
5069 
5070  D3DSTENCILOP_INCRSAT,
5071  D3DSTENCILOP_DECRSAT,
5072 };
5073 
5074 /**
5075  * Set stencil render states.
5076  */
5077 void DXGraphicsStateGuardian9::
5078 do_issue_stencil() {
5079  if (!_supports_stencil) {
5080  return;
5081  }
5082 
5083  const StencilAttrib *stencil = DCAST(StencilAttrib, _target_rs->get_attrib(StencilAttrib::get_class_slot()));
5084 
5085  if (stencil != nullptr) {
5086  // DEBUG
5087  if (false) {
5088  dxgsg9_cat.debug() << "STENCIL STATE CHANGE\n";
5089  dxgsg9_cat.debug() << "\n"
5090  << "SRS_front_comparison_function " << stencil->get_render_state(StencilAttrib::SRS_front_comparison_function) << "\n"
5091  << "SRS_front_stencil_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation) << "\n"
5092  << "SRS_front_stencil_pass_z_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation) << "\n"
5093  << "SRS_front_stencil_pass_z_pass_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation) << "\n"
5094  << "SRS_reference " << stencil->get_render_state(StencilAttrib::SRS_reference) << "\n"
5095  << "SRS_read_mask " << stencil->get_render_state(StencilAttrib::SRS_read_mask) << "\n"
5096  << "SRS_write_mask " << stencil->get_render_state(StencilAttrib::SRS_write_mask) << "\n"
5097  << "SRS_back_comparison_function " << stencil->get_render_state(StencilAttrib::SRS_back_comparison_function) << "\n"
5098  << "SRS_back_stencil_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_back_stencil_fail_operation) << "\n"
5099  << "SRS_back_stencil_pass_z_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_fail_operation) << "\n"
5100  << "SRS_back_stencil_pass_z_pass_operation " << stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_pass_operation) << "\n";
5101  }
5102 
5103  bool on = false;
5104 
5105  unsigned int front_compare;
5106  front_compare = stencil->get_render_state(StencilAttrib::SRS_front_comparison_function);
5107 
5108  if (front_compare != RenderAttrib::M_none) {
5109  set_render_state(D3DRS_STENCILENABLE, TRUE);
5110  set_render_state(D3DRS_STENCILFUNC, dx_stencil_comparison_function_array[front_compare]);
5111  set_render_state(D3DRS_STENCILFAIL, dx_stencil_operation_array[
5112  stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation)]);
5113  set_render_state(D3DRS_STENCILZFAIL, dx_stencil_operation_array[
5114  stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation)]);
5115  set_render_state(D3DRS_STENCILPASS, dx_stencil_operation_array[
5116  stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation)]);
5117  on = true;
5118  } else {
5119  set_render_state(D3DRS_STENCILENABLE, FALSE);
5120  }
5121 
5122  if (_supports_two_sided_stencil) {
5123  unsigned int back_compare;
5124  back_compare = stencil->get_render_state(StencilAttrib::SRS_back_comparison_function);
5125 
5126  if (back_compare != RenderAttrib::M_none) {
5127  set_render_state(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
5128  set_render_state(D3DRS_CCW_STENCILFUNC, dx_stencil_comparison_function_array[back_compare]);
5129  set_render_state(D3DRS_CCW_STENCILFAIL, dx_stencil_operation_array[
5130  stencil->get_render_state(StencilAttrib::SRS_back_stencil_fail_operation)]);
5131  set_render_state(D3DRS_CCW_STENCILZFAIL, dx_stencil_operation_array[
5132  stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_fail_operation)]);
5133  set_render_state(D3DRS_CCW_STENCILPASS, dx_stencil_operation_array[
5134  stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_pass_operation)]);
5135  on = true;
5136  } else {
5137  set_render_state(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
5138  }
5139  }
5140 
5141  if (on) {
5142  set_render_state(D3DRS_STENCILREF, stencil->get_render_state(StencilAttrib::SRS_reference));
5143  set_render_state(D3DRS_STENCILMASK, stencil->get_render_state(StencilAttrib::SRS_read_mask));
5144  set_render_state(D3DRS_STENCILWRITEMASK, stencil->get_render_state(StencilAttrib::SRS_write_mask));
5145  }
5146 
5147  if (stencil->get_render_state(StencilAttrib::SRS_clear)) {
5148  _d3d_device->Clear(0, nullptr, D3DCLEAR_STENCIL, 0, 0.0f, stencil->get_render_state(StencilAttrib::SRS_clear_value));
5149  }
5150 
5151  } else {
5152  // DEBUG
5153  if (false) {
5154  dxgsg9_cat.debug() << "STENCIL STATE CHANGE TO OFF\n";
5155  }
5156 
5157  set_render_state(D3DRS_STENCILENABLE, FALSE);
5158  if (_supports_two_sided_stencil) {
5159  set_render_state(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
5160  }
5161  }
5162 }
5163 
5164 /**
5165  *
5166  */
5167 void DXGraphicsStateGuardian9::
5168 do_issue_scissor() {
5169  const ScissorAttrib *target_scissor = DCAST(ScissorAttrib, _target_rs->get_attrib_def(ScissorAttrib::get_class_slot()));
5170  const LVecBase4 &frame = target_scissor->get_frame();
5171 
5172  RECT r;
5173  r.left = _current_viewport.X + _current_viewport.Width * frame[0];
5174  r.top = _current_viewport.Y + _current_viewport.Height * (1.0f - frame[3]);
5175  r.right = _current_viewport.X + _current_viewport.Width * frame[1];
5176  r.bottom = _current_viewport.Y + _current_viewport.Height * (1.0f - frame[2]);
5177  _d3d_device->SetScissorRect(&r);
5178  set_render_state(D3DRS_SCISSORTESTENABLE, TRUE);
5179 }
5180 
5181 /**
5182  * Convert DirectX framebuffer format ids into a FrameBufferProperties
5183  * structure.
5184  */
5186 calc_fb_properties(DWORD cformat, DWORD dformat,
5187  DWORD multisampletype, DWORD multisamplequality) {
5188  FrameBufferProperties props;
5189  int index=0;
5190  int r=0, g=0, b=0, a=0;
5191  switch (cformat) {
5192  case D3DFMT_R8G8B8: r=8; g=8; b=8; a=0; break;
5193  case D3DFMT_A8R8G8B8: r=8; g=8; b=8; a=8; break;
5194  case D3DFMT_X8R8G8B8: r=8; g=8; b=8; a=0; break;
5195  case D3DFMT_R5G6B5: r=5; g=6; b=5; a=0; break;
5196  case D3DFMT_X1R5G5B5: r=5; g=5; b=5; a=0; break;
5197  case D3DFMT_A1R5G5B5: r=5; g=5; b=5; a=1; break;
5198  case D3DFMT_A4R4G4B4: r=4; g=4; b=4; a=4; break;
5199  case D3DFMT_R3G3B2: r=3; g=3; b=2; a=0; break;
5200  case D3DFMT_A8R3G3B2: r=3; g=3; b=2; a=8; break;
5201  case D3DFMT_X4R4G4B4: r=4; g=4; b=4; a=0; break;
5202  case D3DFMT_A2B10G10R10: r=10;g=10;b=10;a=2; break;
5203  case D3DFMT_A8P8: index=8; a=8; break;
5204  case D3DFMT_P8: index=8; a=0; break;
5205  default: break;
5206  }
5207  if (index > 0) {
5208  props.set_rgb_color(0);
5209  props.set_indexed_color(1);
5210  props.set_color_bits(index);
5211  } else if (r + g + b > 0) {
5212  props.set_rgb_color(1);
5213  props.set_indexed_color(0);
5214  props.set_rgba_bits(r, g, b, a);
5215  }
5216  props.set_alpha_bits(a);
5217 
5218  int depth=0;
5219  int stencil=0;
5220  switch (dformat) {
5221  case D3DFMT_D32: depth=32; stencil=0; break;
5222  case D3DFMT_D15S1: depth=15; stencil=1; break;
5223  case D3DFMT_D24S8: depth=24; stencil=8; break;
5224  case D3DFMT_D16: depth=16; stencil=0; break;
5225  case D3DFMT_D24X8: depth=24; stencil=0; break;
5226  case D3DFMT_D24X4S4: depth=24; stencil=4; break;
5227  default: break;
5228  }
5229  props.set_depth_bits(depth);
5230  props.set_stencil_bits(stencil);
5231  if (multisampletype == D3DMULTISAMPLE_NONMASKABLE) {
5232  props.set_multisamples(2);
5233  } else {
5234  props.set_multisamples(multisampletype);
5235  }
5236  return props;
5237 }
5238 
5239 
5240 #define GAMMA_1 (255.0 * 256.0)
5241 
5242 static bool _gamma_table_initialized = false;
5243 static unsigned short _original_gamma_table [256 * 3];
5244 
5245 void _create_gamma_table_dx9 (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
5246  int i;
5247  double gamma_correction;
5248 
5249  if (gamma <= 0.0) {
5250  // avoid divide by zero and negative exponents
5251  gamma = 1.0;
5252  }
5253  gamma_correction = 1.0 / (double) gamma;
5254 
5255  for (i = 0; i < 256; i++) {
5256  double r;
5257  double g;
5258  double b;
5259 
5260  if (original_red_table) {
5261  r = (double) original_red_table [i] / GAMMA_1;
5262  g = (double) original_green_table [i] / GAMMA_1;
5263  b = (double) original_blue_table [i] / GAMMA_1;
5264  }
5265  else {
5266  r = ((double) i / 255.0);
5267  g = r;
5268  b = r;
5269  }
5270 
5271  r = pow (r, gamma_correction);
5272  g = pow (g, gamma_correction);
5273  b = pow (b, gamma_correction);
5274 
5275  if (r > 1.00) {
5276  r = 1.0;
5277  }
5278  if (g > 1.00) {
5279  g = 1.0;
5280  }
5281  if (b > 1.00) {
5282  b = 1.0;
5283  }
5284 
5285  r = r * GAMMA_1;
5286  g = g * GAMMA_1;
5287  b = b * GAMMA_1;
5288 
5289  red_table [i] = r;
5290  green_table [i] = g;
5291  blue_table [i] = b;
5292  }
5293 }
5294 
5295 /**
5296  * Static function for getting the original gamma.
5297  */
5300  bool get;
5301 
5302  get = false;
5303  if (_gamma_table_initialized == false) {
5304  HDC hdc = GetDC(nullptr);
5305 
5306  if (hdc) {
5307  if (GetDeviceGammaRamp (hdc, (LPVOID) _original_gamma_table)) {
5308  _gamma_table_initialized = true;
5309  get = true;
5310  }
5311 
5312  ReleaseDC (nullptr, hdc);
5313  }
5314  }
5315 
5316  return get;
5317 }
5318 
5319 /**
5320  * Static function for setting gamma which is needed for atexit.
5321  */
5323 static_set_gamma(bool restore, PN_stdfloat gamma) {
5324  bool set;
5325  HDC hdc = GetDC(nullptr);
5326 
5327  set = false;
5328  if (hdc) {
5329  unsigned short ramp [256 * 3];
5330 
5331  if (restore && _gamma_table_initialized) {
5332  _create_gamma_table_dx9 (gamma, &_original_gamma_table [0], &_original_gamma_table [256], &_original_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
5333  }
5334  else {
5335  _create_gamma_table_dx9 (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]);
5336  }
5337 
5338  if (SetDeviceGammaRamp (hdc, ramp)) {
5339  set = true;
5340  }
5341 
5342  ReleaseDC (nullptr, hdc);
5343  }
5344 
5345  return set;
5346 }
5347 
5348 /**
5349  * Non static version of setting gamma. Returns true on success.
5350  */
5352 set_gamma(PN_stdfloat gamma) {
5353  bool set;
5354 
5355  set = static_set_gamma(false, gamma);
5356  if (set) {
5357  _gamma = gamma;
5358  }
5359 
5360  return set;
5361 }
5362 
5363 /**
5364  * Restore original gamma.
5365  */
5368  static_set_gamma(true, 1.0f);
5369 }
5370 
5371 /**
5372  * This function is passed to the atexit function.
5373  */
5376  set_cg_device(nullptr);
5377  static_set_gamma(true, 1.0f);
5378 }
5379 
5380 /**
5381  * Returns true if this particular GSG supports the specified Cg Shader
5382  * Profile.
5383  */
5385 get_supports_cg_profile(const std::string &name) const {
5386 #ifndef HAVE_CG
5387  return false;
5388 #else
5389  CGprofile profile = cgGetProfile(name.c_str());
5390 
5391  if (profile == CG_PROFILE_UNKNOWN) {
5392  dxgsg9_cat.error() << name <<", unknown Cg-profile\n";
5393  return false;
5394  }
5395  return cgD3D9IsProfileSupported(cgGetProfile(name.c_str())) != 0;
5396 #endif // HAVE_CG
5397 }
5398 
5399 /**
5400  * Sets the global Cg device pointer. TODO: make this thread-safe somehow.
5401  * Maybe Cg is inherently not thread-safe.
5402  */
5404 set_cg_device(LPDIRECT3DDEVICE9 cg_device) {
5405 #ifdef HAVE_CG
5406  if (_cg_device != cg_device) {
5407  cgD3D9SetDevice(cg_device);
5408  _cg_device = cg_device;
5409  }
5410 #endif // HAVE_CG
5411 }
5412 
5413 /**
5414  * Returns a vertex buffer containing only a full-white color.
5415  */
5416 LPDIRECT3DVERTEXBUFFER9 DXGraphicsStateGuardian9::
5418  if (_white_vbuffer != nullptr) {
5419  return _white_vbuffer;
5420  }
5421 
5422  LPDIRECT3DVERTEXBUFFER9 vbuffer;
5423  HRESULT hr;
5424  hr = _screen->_d3d_device->CreateVertexBuffer(sizeof(D3DCOLOR), D3DUSAGE_WRITEONLY, D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &vbuffer, nullptr);
5425 
5426  if (FAILED(hr)) {
5427  dxgsg9_cat.error()
5428  << "CreateVertexBuffer failed" << D3DERRORSTRING(hr);
5429  return nullptr;
5430  }
5431 
5432  D3DCOLOR *local_pointer;
5433  hr = vbuffer->Lock(0, sizeof(D3DCOLOR), (void **) &local_pointer, D3DLOCK_DISCARD);
5434  if (FAILED(hr)) {
5435  dxgsg9_cat.error()
5436  << "VertexBuffer::Lock failed" << D3DERRORSTRING(hr);
5437  return false;
5438  }
5439 
5440  *local_pointer = D3DCOLOR_ARGB(255, 255, 255, 255);
5441 
5442  vbuffer->Unlock();
5443  _white_vbuffer = vbuffer;
5444  return vbuffer;
5445 }
5446 
5447 typedef std::string KEY;
5448 
5449 typedef struct _KEY_ELEMENT
5450 {
5451  KEY key;
5452  int count;
5453  int secondary_count;
5454 
5455  struct _KEY_ELEMENT *next;
5456 }
5457 KEY_ELEMENT;
5458 
5459 typedef struct _KEY_LIST
5460 {
5461  int total_key_elements;
5462  KEY_ELEMENT *key_element;
5463 }
5464 KEY_LIST;
5465 
5466 KEY_ELEMENT *new_key_element (KEY key, KEY_LIST *key_list)
5467 {
5468  KEY_ELEMENT *key_element;
5469 
5470  key_element = new KEY_ELEMENT;
5471  key_element -> key = key;
5472  key_element -> count = 1;
5473  key_element -> secondary_count = 0;
5474  key_element -> next = 0;
5475 
5476  key_list -> total_key_elements++;
5477 
5478  return key_element;
5479 }
5480 
5481 KEY_ELEMENT *first_key_element (KEY_LIST *key_list)
5482 {
5483  return key_list -> key_element;
5484 }
5485 
5486 KEY_ELEMENT *next_key_element (KEY_ELEMENT *key_element)
5487 {
5488  return key_element -> next;
5489 }
5490 
5491 void delete_key_list (KEY_LIST *key_list)
5492 {
5493  if (key_list)
5494  {
5495  KEY_ELEMENT *key_element;
5496  KEY_ELEMENT *key_element_next;
5497 
5498  key_element = first_key_element (key_list);
5499  while (key_element)
5500  {
5501  key_element_next = next_key_element (key_element);
5502  delete key_element;
5503  key_element = key_element_next;
5504  }
5505 
5506  delete key_list;
5507  }
5508 }
5509 
5510 KEY_LIST *new_key_list (void)
5511 {
5512  KEY_LIST *key_list;
5513 
5514  key_list = new KEY_LIST;
5515  memset (key_list, 0, sizeof (KEY_LIST));
5516 
5517  return key_list;
5518 }
5519 
5520 KEY_ELEMENT *add_to_key_list (KEY key, KEY_LIST *key_list)
5521 {
5522  KEY_ELEMENT *key_element;
5523  KEY_ELEMENT *last_key_element;
5524  KEY_ELEMENT *current_key_element;
5525 
5526  key_element = 0;
5527  last_key_element = 0;
5528  current_key_element = key_list -> key_element;
5529  if (current_key_element == 0)
5530  {
5531  key_element = new_key_element (key, key_list);
5532  key_list -> key_element = key_element;
5533  }
5534  else
5535  {
5536  while (current_key_element)
5537  {
5538  if (key < current_key_element -> key)
5539  {
5540  key_element = new_key_element (key, key_list);
5541  key_element -> next = current_key_element;
5542 
5543  if (last_key_element == 0)
5544  {
5545  key_list -> key_element = key_element;
5546  }
5547  else
5548  {
5549  last_key_element -> next = key_element;
5550  }
5551  break;
5552  }
5553  else
5554  {
5555  if (key > current_key_element -> key)
5556  {
5557  if (current_key_element -> next == 0)
5558  {
5559  key_element = new_key_element (key, key_list);
5560  current_key_element -> next = key_element;
5561  break;
5562  }
5563  else
5564  {
5565 
5566  }
5567  }
5568  else
5569  {
5570  current_key_element -> count++;
5571  break;
5572  }
5573  }
5574 
5575  last_key_element = current_key_element;
5576  current_key_element = current_key_element -> next;
5577  }
5578  }
5579 
5580  return key_element;
5581 }
CombineSource get_combine_alpha_source2() const
Get source2 of combine_alpha_mode.
Definition: textureStage.I:583
void get_linear_range(PN_stdfloat &onset, PN_stdfloat &opaque)
Retrieves the current onset and offset ranges.
Definition: fog.cxx:173
get_animation_type
Returns the type of animation represented by this spec.
virtual bool is_linear() const
Returns true if the lens represents a linear projection (e.g.
Definition: lens.cxx:540
IDirect3DTexture9 * get_d3d_2d_texture() const
Returns the Direct3D object that represents the texture, in the case of a 1-d or 2-d texture.
A light shining from infinitely far away in a particular direction, like sunlight.
get_y_size
Returns the height of the texture image in texels.
Definition: texture.h:338
static bool is_srgb(Format format)
Returns true if the indicated format is in the sRGB color space, false otherwise.
Definition: texture.cxx:2617
Texture * get_texture() const
Returns the pointer to the associated Texture object.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool was_modified(const GeomVertexArrayDataHandle *reader) const
Returns true if the data has been modified since the last time mark_loaded() was called.
get_mode
Returns the shade mode.
get_wrap_u
Returns the wrap mode of the texture in the U direction.
Definition: samplerState.h:112
bool setup_array_data(DXVertexBufferContext9 *&vbc, const GeomVertexArrayDataHandle *data, bool force)
Internal function to bind a buffer object for the indicated data array, if appropriate,...
The abstract interface to all kinds of lights.
Definition: light.h:38
HRESULT set_sampler_state(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value)
This function creates a common layer between DX and Panda.
virtual void end_frame(Thread *current_thread)
Called after each frame is rendered, to allow the GSG a chance to do any internal cleanup after rende...
Encapsulates the data from a DisplayRegion, pre-fetched for one stage of the pipeline.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void release_shader(ShaderContext *sc)
Releases the resources allocated by prepare_shader.
get_animation
Returns the GeomVertexAnimationSpec that indicates how this format's vertices are set up for animatio...
Indicates a coordinate-system transform on vertices.
bool do_framebuffer_copy_to_ram(Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb, bool inverted)
This is the implementation of framebuffer_copy_to_ram(); it adds one additional parameter,...
get_tex_view_offset
Returns the current setting of the tex_view_offset.
Definition: textureStage.h:203
get_mode
Returns the transparency mode.
get_num_transforms
Returns the number of transforms in the table.
This is a base class for GraphicsWindow (actually, GraphicsOutput) and DisplayRegion,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Enables or disables writing to the depth buffer.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void clear(DrawableRegion *clearable)
Clears all of the indicated buffers to their assigned colors.
LPDIRECT3DVERTEXBUFFER9 get_white_vbuffer()
Returns a vertex buffer containing only a full-white color.
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
has_ambient
Returns true if the ambient color has been explicitly set for this material, false otherwise.
Definition: material.h:114
get_z_size
Returns the depth of the texture image in texels.
Definition: texture.h:342
CombineOperand get_combine_alpha_operand0() const
Get operand0 of combine_alpha_mode.
Definition: textureStage.I:559
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static bool static_set_gamma(bool restore, PN_stdfloat gamma)
Static function for setting gamma which is needed for atexit.
Enables or disables writing to the color buffer.
HRESULT set_texture_stage_state(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
This function creates a common layer between DX and Panda.
get_component_type
Returns the numeric interpretation of each component of the texture.
Definition: texture.h:366
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.
get_reference_alpha
Returns the alpha reference value.
virtual bool extract_texture_data(Texture *tex)
This method should only be called by the GraphicsEngine.
bool might_have_ram_image() const
Returns true if the texture's image contents are currently available in main RAM, or there is reason ...
Definition: texture.I:1264
void get_region_pixels_i(int &xo, int &yo, int &w, int &h) const
Similar to get_region_pixels(), but returns the upper left corner, and the pixel numbers are numbered...
Indicates which, if any, material should be applied to geometry.
This object describes how the vertex animation, if any, represented in a GeomVertexData is encoded.
Enables or disables writing to the depth buffer.
virtual void prepare_display_region(DisplayRegionPipelineReader *dr)
Makes the specified DisplayRegion current.
bool bind(GSG *gsg)
This function is to be called to enable a new shader.
virtual void end_draw_primitives()
Called after a sequence of draw_primitive() functions are called, this should do whatever cleanup is ...
void release_all()
Releases all prepared objects.
This controls the enabling of transparency.
virtual bool draw_triangles(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of disconnected triangles.
Objects of this class are used to convert vertex data from a Geom into a format suitable for passing ...
Definition: geomMunger.h:50
This is a special class object that holds all the information returned by a particular GSG to indicat...
get_fog
If the FogAttrib is not an 'off' FogAttrib, returns the fog that is associated.
Definition: fogAttrib.h:38
get_mode
Returns the render mode.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
Caches a GeomVertexArrayData in the DirectX device as a vertex buffer.
get_effective_magfilter
Returns the filter mode of the texture for magnification, with special treatment for FT_default.
Definition: samplerState.h:118
get_texture_type
Returns the overall interpretation of the texture.
Definition: texture.h:357
void setup_texture(TextureType texture_type, int x_size, int y_size, int z_size, ComponentType component_type, Format format)
Sets the texture to the indicated type and dimensions, presumably in preparation for calling read() o...
Definition: texture.I:52
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
Specifies whether flat shading (per-polygon) or smooth shading (per-vertex) is in effect.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Definition: shader.h:49
void apply_texture(int i, TextureContext *tc, const SamplerState &sampler)
Makes the texture the currently available texture for rendering on the ith stage.
This is a special class object that holds all the information returned by a particular GSG to indicat...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_point
Returns the point in space at which the light is located.
Definition: pointLight.h:57
virtual VertexBufferContext * prepare_vertex_buffer(GeomVertexArrayData *data)
Creates a new retained-mode representation of the given data, and returns a newly-allocated VertexBuf...
void unbind(GSG *gsg)
This function disables a currently-bound shader.
bool create_texture(DXScreenData &scrn)
Use panda texture's pixelbuffer to create a texture for the specified device.
get_wrap_w
Returns the wrap mode of the texture in the W direction.
Definition: samplerState.h:114
static D3DFORMAT get_index_type(Geom::NumericType numeric_type)
Maps from the Geom's internal numeric type symbols to DirectX's.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void issue_parameters(GSG *gsg, int altered)
This function gets called whenever the RenderState or TransformState has changed, but the Shader itse...
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void disable_shader_texture_bindings(GSG *gsg)
Disable all the texture bindings used by this shader.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Caches a GeomPrimitive in the DirectX device as an index buffer.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool was_simple_image_modified() const
Returns true if the texture's "simple" image has been modified since the last time mark_simple_loaded...
get_clear_stencil
Returns the current clear stencil value.
virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader, const GeomVertexDataPipelineReader *data_reader, bool force)
Called before a sequence of draw_primitive() functions are called, this should prepare the vertex dat...
PN_stdfloat get_hfov() const
Returns the horizontal component of fov only.
Definition: lens.I:344
int get_num_combine_alpha_operands() const
Returns the number of meaningful operands that may be retrieved via get_combine_alpha_sourceN() and g...
Definition: textureStage.I:543
get_clear_color
Returns the current clear color value.
virtual void set_state_and_transform(const RenderState *state, const TransformState *transform)
Simultaneously resets the render state and the transform state.
CombineOperand get_combine_rgb_operand1() const
Get operand1 of combine_rgb_mode.
Definition: textureStage.I:437
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
Encapsulates the data from a Geom, pre-fetched for one stage of the pipeline.
Definition: geom.h:405
void do_issue_color()
This method is defined in the base class because it is likely that this functionality will be used fo...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_effective_minfilter
Returns the filter mode of the texture for minification, with special treatment for FT_default.
Definition: samplerState.h:117
void mark_loaded(const GeomVertexArrayDataHandle *reader)
Should be called after the VertexBufferContext has been loaded into graphics memory,...
get_specular_color
Returns the color of specular highlights generated by the light.
Definition: spotlight.h:56
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:1242
get_mode
Returns the depth write mode.
bool has_mipmaps() const
Returns true if the texture was created with mipmaps, false otherwise.
virtual void end_scene()
Called between begin_frame() and end_frame() to mark the end of drawing commands for a "scene" (usual...
ShaderLanguage get_language() const
Returns the shader language in which this shader was written.
Definition: shader.I:132
static bool get_gamma_table(void)
Static function for getting the original gamma.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool framebuffer_copy_to_texture(Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb)
Copy the pixels within the indicated display region from the framebuffer into texture memory.
get_mat
Returns the matrix that describes the transform.
get_channels
Returns the mask of color channels that are enabled by this attrib.
get_local
Returns the local viewer flag.
Definition: material.h:128
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CombineSource get_combine_rgb_source1() const
Get source1 of combine_rgb_mode.
Definition: textureStage.I:429
get_diffuse
Returns the diffuse color setting, if it has been set.
Definition: material.h:116
static void atexit_function(void)
This function is passed to the atexit function.
get_rgb_scale
See set_rgb_scale().
Definition: textureStage.h:199
has_base_color
Returns true if the base color has been explicitly set for this material, false otherwise.
Definition: material.h:112
get_emission
Returns the emission color setting, if it has been set.
Definition: material.h:120
The ShaderContext is meant to contain the compiled version of a shader string.
Definition: shaderContext.h:31
void disable_shader_vertex_arrays(GSG *gsg)
Disable all the vertex arrays used by this shader.
get_alpha_mode
Returns the blending mode for the alpha channel.
void enqueue_lru(AdaptiveLru *lru)
Adds the page to the LRU for the first time, or marks it recently-accessed if it has already been add...
get_operand_b
Returns the RGB multiplier for the second component.
GraphicsEngine * get_engine() const
Returns the graphics engine that created this GSG.
Lens * get_lens(int index=0) const
Returns a pointer to the particular Lens associated with this LensNode, or NULL if there is not yet a...
Definition: lensNode.I:47
has_diffuse
Returns true if the diffuse color has been explicitly set for this material, false otherwise.
Definition: material.h:116
Indicates which faces should be culled based on their vertex ordering.
virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader, const GeomVertexDataPipelineReader *data_reader, bool force)
Called before a sequence of draw_primitive() functions are called, this should prepare the vertex dat...
void reset_all_windows(bool swapchain)
Resets the framebuffer of the current window.
Applies a Fog to the geometry at and below this node.
Definition: fogAttrib.h:25
get_mode
Return the mode of this stage.
Definition: textureStage.h:196
set_render_to_texture
Sets a flag on the texture that indicates whether the texture is intended to be used as a direct-rend...
Definition: texture.h:409
void set_size_padded(int x=1, int y=1, int z=1)
Changes the size of the texture, padding if necessary, and setting the pad region as well.
Definition: texture.cxx:1907
A lightweight class that represents a single element that may be timed and/or counted via stats.
get_wrap_v
Returns the wrap mode of the texture in the V direction.
Definition: samplerState.h:113
get_mode
Returns the blending mode for the RGB channels.
get_exp_density
Returns the density of the fog for exponential calculations.
Definition: fog.h:86
get_format
Returns the format of the texture, which represents both the semantic meaning of the texels and,...
Definition: texture.h:362
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_num_transforms
This is only meaningful for animation_type AT_hardware.
CombineSource get_combine_alpha_source0() const
Get source0 of combine_alpha_mode.
Definition: textureStage.I:551
bool was_modified(const GeomPrimitivePipelineReader *reader) const
Returns true if the data has been modified since the last time mark_loaded() was called.
An offscreen render buffer.
bool check_dx_allocation(HRESULT result, int allocation_size, int attempts)
This function is called after the creation of textures, vertex buffers, and index buffers to check if...
get_effective_anisotropic_degree
Returns the degree of anisotropic filtering that should be applied to the texture.
Definition: samplerState.h:120
get_offset
Returns the depth offset represented by this attrib.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A StencilAttrib is a collection of all stencil render states.
Definition: stencilAttrib.h:28
get_transform
Returns the nth transform in the table.
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...
CombineSource get_combine_rgb_source2() const
Get source2 of combine_rgb_mode.
Definition: textureStage.I:445
virtual bool get_supports_cg_profile(const std::string &name) const
Returns true if this particular GSG supports the specified Cg Shader Profile.
void restore_gamma()
Restore original gamma.
IDirect3DBaseTexture9 * get_d3d_texture() const
Returns the Direct3D object that represents the texture, whatever kind of texture it is.
get_shininess
Returns the shininess exponent of the material.
Definition: material.h:122
static void set_cg_device(LPDIRECT3DDEVICE9 cg_device)
Sets the global Cg device pointer.
const LPlane & get_plane() const
Returns the plane represented by the PlaneNode.
Definition: planeNode.I:54
void mark_new()
Marks the GSG as "new", so that the next call to reset_if_new() will be effective.
virtual void reset()
Resets all internal state as if the gsg were newly created.
virtual bool draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of line strips.
Specifies how atmospheric fog effects are applied to geometry.
Definition: fog.h:41
bool get_clear_color_active() const
Returns the current setting of the flag that indicates whether the color buffer should be cleared eve...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CombineOperand get_combine_rgb_operand0() const
Get operand0 of combine_rgb_mode.
Definition: textureStage.I:421
get_lod_bias
Returns the bias that will be added to the texture level of detail when sampling this texture.
Definition: samplerState.h:124
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
bool get_clear_depth_active() const
Returns the current setting of the flag that indicates whether the depth buffer should be cleared eve...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ShaderContext * prepare_shader(Shader *se)
Compile a vertex/fragment shader body.
virtual void begin_occlusion_query()
Begins a new occlusion query.
This specialization on GeomMunger finesses vertices for DirectX rendering.
Definition: dxGeomMunger9.h:29
A light originating from a single point in space, and shining in a particular direction,...
Definition: spotlight.h:32
get_ambient
Returns the ambient color setting, if it has been set.
Definition: material.h:114
int get_num_combine_rgb_operands() const
Returns the number of meaningful operands that may be retrieved via get_combine_rgb_sourceN() and get...
Definition: textureStage.I:405
get_exponent
Returns the exponent that controls the amount of light falloff from the center of the spotlight.
Definition: spotlight.h:51
virtual void do_issue_light()
This implementation of do_issue_light() assumes we have a limited number of hardware lights available...
void get_region_pixels_i(int &xo, int &yo, int &w, int &h) const
Similar to get_region_pixels(), but returns the upper left corner, and the pixel numbers are numbered...
bool apply_index_buffer(IndexBufferContext *ibc, const GeomPrimitivePipelineReader *reader, bool force)
Updates the index buffer with the current data, and makes it the current index buffer for rendering.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_saved_result
Returns the current setting of the saved_result flag.
Definition: textureStage.h:201
bool get_clear_stencil_active() const
Returns the current setting of the flag that indicates whether the color buffer should be cleared eve...
get_indexed_transforms
This is only meaningful for animation_type AT_hardware.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool set_gamma(PN_stdfloat gamma)
Non static version of setting gamma.
CombineMode get_combine_alpha_mode() const
Get combine_alpha_mode.
Definition: textureStage.I:534
get_mode
Returns the depth write mode.
set_color_bits
Sets the number of requested color bits as a single number that represents the sum of the individual ...
virtual void end_frame(Thread *current_thread)
Called after each frame is rendered, to allow the GSG a chance to do any internal cleanup after rende...
get_alpha_scale
See set_alpha_scale().
Definition: textureStage.h:200
get_clear_depth
Returns the current clear depth value.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void end_draw_primitives()
Called after a sequence of draw_primitive() functions are called, this should do whatever cleanup is ...
get_color
return the color for this stage
Definition: textureStage.h:198
Enables or disables writing of pixel to framebuffer based on its alpha value relative to a reference ...
CombineOperand get_combine_alpha_operand1() const
Get operand1 of combine_alpha_mode.
Definition: textureStage.I:575
virtual bool update_texture(TextureContext *tc, bool force)
Ensures that the current Texture data is refreshed onto the GSG.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Defines the way an object appears in the presence of lighting.
Definition: material.h:43
bool upload_data(const GeomPrimitivePipelineReader *reader, bool force)
Copies the latest data from the client store to DirectX.
get_color
Returns the color of the fog.
Definition: fog.h:68
get_nodal_point
Returns the center point of the lens: the point from which the lens is viewing.
Definition: lens.h:129
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
get_num_views
Returns the number of "views" in the texture.
Definition: texture.h:346
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static void add_gsg(GraphicsStateGuardianBase *gsg)
Called by a GSG after it has been initialized, to add a new GSG to the available list.
Represents a set of settings that indicate how a texture is sampled.
Definition: samplerState.h:36
CPT(TransformState) DXGraphicsStateGuardian9
Given a lens, calculates the appropriate projection matrix for use with this gsg.
void mark_loaded(const GeomPrimitivePipelineReader *reader)
Should be called after the IndexBufferContext has been loaded into graphics memory,...
virtual TextureContext * prepare_texture(Texture *tex, int view)
Creates a new retained-mode representation of the given texture, and returns a newly-allocated Textur...
TextureContext * prepare_now(int view, PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the texture on the particular GSG, if it does not already exist.
Definition: texture.cxx:1956
virtual void bind_light(PointLight *light_obj, const NodePath &light, int light_id)
Called the first time a particular light has been bound to a given id within a frame,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class defines the physical layout of the vertex data stored within a Geom.
bool apply_vertex_buffer(VertexBufferContext *vbc, const GeomVertexArrayDataHandle *reader, bool force)
Updates the vertex buffer with the current data, and makes it the current vertex buffer for rendering...
const unsigned char * get_read_pointer(bool force) const
Returns a readable pointer to the beginning of the actual data stream, or NULL if the data is not cur...
PT(OcclusionQueryContext) DXGraphicsStateGuardian9
Ends a previous call to begin_occlusion_query().
Applies a transform matrix to UV's before they are rendered.
get_material
If the MaterialAttrib is not an 'off' MaterialAttrib, returns the material that is associated.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static DWORD LColor_to_D3DCOLOR(const LColor &cLColor)
Converts Panda's floating-point LColor structure to DirectX's D3DCOLOR packed structure.
get_frame
Returns the left, right, bottom, top coordinates of the scissor frame.
Definition: scissorAttrib.h:51
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const LMatrix4 & get_projection_mat(StereoChannel channel=SC_mono) const
Returns the complete transformation matrix from a 3-d point in space to a point on the film,...
Definition: lens.I:563
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool prepare_lens()
Makes the current lens (whichever lens was most recently specified with set_scene()) active,...
Stores the total set of VertexTransforms that the vertices in a particular GeomVertexData object migh...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This specifies how colors are blended into the frame buffer, for special effects.
get_effective_mode
Returns the effective culling mode.
CombineMode get_combine_rgb_mode() const
Get the combine_rgb_mode.
Definition: textureStage.I:396
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CombineSource get_combine_rgb_source0() const
Get source0 of combine_rgb_mode.
Definition: textureStage.I:413
void set_rgba_bits(int r, int g, int b, int a)
Convenience method for setting the red, green, blue and alpha bits in one go.
get_stride
Returns the total number of bytes reserved in the array for each vertex.
bool update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force)
Disables all vertex arrays used by the previous shader, then enables all the vertex arrays needed by ...
virtual bool draw_lines(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of disconnected line segments.
get_mode
Returns the render mode.
A thread; that is, a lightweight process.
Definition: thread.h:46
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.
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
virtual void prepare_display_region(DisplayRegionPipelineReader *dr)
Prepare a display region for rendering (set up scissor region and viewport)
get_direction
Returns the direction in which the light is aimed.
get_border_color
Returns the solid color of the texture's border.
Definition: samplerState.h:121
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a special kind of attribute that instructs the graphics driver to apply an offset or bias to ...
virtual bool begin_frame(Thread *current_thread)
Called before each frame is rendered, to allow the GSG a chance to do any internal cleanup before beg...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool involves_color_scale() const
Returns true if the TextureStage is affected by the setting of the current ColorScaleAttrib,...
Definition: textureStage.I:600
get_alpha_operand_a
Returns the alpha multiplier for the first component.
void mark_loaded()
Should be called after the texture has been loaded into graphics memory, this updates the internal fl...
This is a special class object that holds all the information returned by a particular GSG to indicat...
virtual void release_vertex_buffer(VertexBufferContext *vbc)
Frees the GL resources previously allocated for the data.
Encapsulates all the communication with a particular instance of a given rendering backend.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Specifies how polygons are to be drawn.
unsigned int get_render_state(StencilRenderState render_state_identifier) const
Returns render state.
Definition: stencilAttrib.I:18
This describes the structure of a single array within a Geom data.
void set_active(bool flag)
Changes the active flag associated with this object.
Definition: bufferContext.I:65
bool is_off() const
Returns true if the MaterialAttrib is an 'off' MaterialAttrib, indicating that it should disable the ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void end_scene()
Called between begin_frame() and end_frame() to mark the end of drawing commands for a "scene" (usual...
get_thickness
Returns the line width or point thickness.
get_color
Returns the basic color of the light.
Definition: light.h:49
bool changed_size(const GeomVertexArrayDataHandle *reader) const
Returns true if the data has changed size since the last time mark_loaded() was called.
FrameBufferProperties calc_fb_properties(DWORD cformat, DWORD dformat, DWORD multisampletype, DWORD multisamplequality)
Convert DirectX framebuffer format ids into a FrameBufferProperties structure.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_perspective
Returns the perspective flag.
Specifies how polygons are to be drawn.
int release_all_index_buffers()
Frees the resources for all index buffers associated with this GSG.
A rectangular subregion within a window for rendering into.
Definition: displayRegion.h:57
CombineOperand get_combine_rgb_operand2() const
Get operand2 of combine_rgb_mode.
Definition: textureStage.I:453
virtual bool draw_trifans(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of triangle fans.
Encapsulates the data from a GeomVertexData, pre-fetched for one stage of the pipeline.
int release_all_vertex_buffers()
Frees the resources for all vertex buffers associated with this GSG.
CombineSource get_combine_alpha_source1() const
Get source1 of combine_alpha_mode.
Definition: textureStage.I:567
CombineOperand get_combine_alpha_operand2() const
Get operand2 of combine_alpha_mode.
Definition: textureStage.I:591
get_prepared_objects
Returns the set of texture and geom objects that have been prepared with this GSG (and possibly other...
This restricts rendering to within a rectangular region of the scene, without otherwise affecting the...
Definition: scissorAttrib.h:36
bool uses_color() const
Returns true if the TextureStage makes use of whatever color is specified in set_color(),...
Definition: textureStage.I:609
virtual void release_texture(TextureContext *tc)
Frees the GL resources previously allocated for the texture.
Returned from a GSG in response to begin_occlusion_query() .
This class is the main interface to controlling the render process.
virtual void reset()
Resets all internal state as if the gsg were newly created.
void mark_unloaded()
Should be called after the texture has been forced out of texture memory.
virtual bool begin_scene()
Called between begin_frame() and end_frame() to mark the beginning of drawing commands for a "scene" ...
get_operand_a
Returns the RGB multiplier for the first component.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
has_simple_ram_image
Returns true if the Texture has a "simple" image available in main RAM.
Definition: texture.h:509
virtual bool begin_frame(Thread *current_thread)
Called before each frame is rendered, to allow the GSG a chance to do any internal cleanup before beg...
void create_ibuffer(DXScreenData &scrn, const GeomPrimitivePipelineReader *reader)
Creates a new index buffer (but does not upload data to it).
virtual IndexBufferContext * prepare_index_buffer(GeomPrimitive *data)
Creates a new retained-mode representation of the given data, and returns a newly-allocated IndexBuff...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:758
get_specular
Returns the specular color setting, if it has been set.
Definition: material.h:118
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of triangle strips.
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
bool is_off() const
Returns true if the FogAttrib is an 'off' FogAttrib, indicating that it should disable fog.
Definition: fogAttrib.I:26
get_mode
Returns the alpha write mode.
Encapsulates the data from a GeomPrimitive, pre-fetched for one stage of the pipeline.
bool changed_size(const GeomPrimitivePipelineReader *reader) const
Returns true if the data has changed size since the last time mark_loaded() was called.
get_specular_color
Returns the color of specular highlights generated by the light.
Definition: pointLight.h:45
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
bool upload_texture(DXTextureContext9 *dtc, bool force)
Creates a texture surface on the graphics card and fills it with its pixel data.
void update_shader_texture_bindings(DXShaderContext9 *prev, GSG *gsg)
Disables all texture bindings used by the previous shader, then enables all the texture bindings need...
get_attenuation
Returns the terms of the attenuation equation for the light.
Definition: pointLight.h:49
ShaderContext * prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the shader on the particular GSG, if it does not already exist.
Definition: shader.cxx:3703
HRESULT set_render_state(D3DRENDERSTATETYPE state, DWORD value)
This function creates a common layer between DX and Panda for SetRenderState.
get_alpha_operand_b
Returns the alpha multiplier for the second component.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A RenderBuffer is an arbitrary subset of the various layers (depth buffer, color buffer,...
Definition: renderBuffer.h:27
bool was_modified() const
Returns true if the texture properties or image have been modified since the last time mark_loaded() ...
virtual bool framebuffer_copy_to_ram(Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb)
Copy the pixels within the indicated display region from the framebuffer into system memory,...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
virtual bool draw_points(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of disconnected points.
const LVector3 & get_view_vector() const
Returns the axis along which the lens is facing.
Definition: lens.cxx:214
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A light originating from a single point in space, and shining in all directions.
Definition: pointLight.h:25
void delete_texture()
Release the surface used to store the texture.
get_x_size
Returns the width of the texture image in texels.
Definition: texture.h:334
A node that contains a plane.
Definition: planeNode.h:36
has_specular
Returns true if the specular color has been explicitly set for this material, false otherwise.
Definition: material.h:118
Similar to PointerToArray, except that its contents may not be modified.
This is the data for one array of a GeomVertexData structure.
get_attenuation
Returns the terms of the attenuation equation for the light.
Definition: spotlight.h:60
virtual bool begin_scene()
Called between begin_frame() and end_frame() to mark the beginning of drawing commands for a "scene" ...
get_specular_color
Returns the color of specular highlights generated by the light.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_ram_image_compression
Returns the compression mode in which the ram image is already stored pre- compressed.
Definition: texture.h:463
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void release_index_buffer(IndexBufferContext *ibc)
Frees the GL resources previously allocated for the data.
bool has_uncompressed_ram_image() const
Returns true if the Texture has its image contents available in main RAM and is uncompressed,...
Definition: texture.I:1252