From 0aeb31a2b442244e04a631af1b791c1ce07e744d Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 1 Dec 2005 18:27:08 +0000 Subject: [PATCH] further hacks around 64K client buffer bug--indexed geometry --- panda/src/dxgsg8/dxGraphicsStateGuardian8.I | 20 ++++ panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx | 97 +++++++++++++------ panda/src/dxgsg8/dxGraphicsStateGuardian8.h | 11 +++ 3 files changed, 99 insertions(+), 29 deletions(-) diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.I b/panda/src/dxgsg8/dxGraphicsStateGuardian8.I index 2e13521cc4..33ff8140cb 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.I +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.I @@ -128,3 +128,23 @@ INLINE D3DTRANSFORMSTATETYPE DXGraphicsStateGuardian8:: get_tex_mat_sym(int stage_index) { return (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + stage_index); } + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian8::get_safe_buffer_start +// Access: Protected, Static +// Description: Returns the address of a 64K buffer that is allocated +// at the beginning of a 64K block. +//////////////////////////////////////////////////////////////////// +INLINE unsigned char *DXGraphicsStateGuardian8:: +get_safe_buffer_start() { + if (_temp_buffer == NULL) { + // Guarantee we get a buffer of size 0x10000 bytes that begins + // on an even multiple of 0x10000. We do this by allocating + // double the required buffer, and then pointing to the first + // multiple of 0x10000 within that buffer. + _temp_buffer = new unsigned char[0x1ffff]; + _safe_buffer_start = (unsigned char *)(((long)_temp_buffer + 0xffff) & ~0xffff); + } + + return _safe_buffer_start; +} diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index fe3c347dd7..d16c0de2b6 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -68,6 +68,8 @@ TypeHandle DXGraphicsStateGuardian8::_type_handle; D3DMATRIX DXGraphicsStateGuardian8::_d3d_ident_mat; +unsigned char *DXGraphicsStateGuardian8::_temp_buffer = NULL; +unsigned char *DXGraphicsStateGuardian8::_safe_buffer_start = NULL; #define __D3DLIGHT_RANGE_MAX ((float)sqrt(FLT_MAX)) //for some reason this is missing in dx8 hdrs @@ -905,10 +907,9 @@ draw_triangles(const GeomTriangles *primitive) { } else { // Indexed, client arrays. D3DFORMAT index_type = get_index_type(primitive->get_index_type()); - - _d3d_device->DrawIndexedPrimitiveUP + draw_indexed_primitive_up (D3DPT_TRIANGLELIST, - min_vertex, max_vertex - min_vertex + 1, + min_vertex, max_vertex, primitive->get_num_primitives(), primitive->get_data(), index_type, @@ -965,9 +966,9 @@ draw_tristrips(const GeomTristrips *primitive) { } else { // Indexed, client arrays, one long triangle strip. D3DFORMAT index_type = get_index_type(primitive->get_index_type()); - _d3d_device->DrawIndexedPrimitiveUP + draw_indexed_primitive_up (D3DPT_TRIANGLESTRIP, - min_vertex, max_vertex - min_vertex + 1, + min_vertex, max_vertex, primitive->get_num_vertices() - 2, primitive->get_data(), index_type, _vertex_data->get_array(0)->get_data(), @@ -1039,9 +1040,9 @@ draw_tristrips(const GeomTristrips *primitive) { _vertices_tristrip_pcollector.add_level(ends[i] - start); unsigned int min = mins.get_data1i(); unsigned int max = maxs.get_data1i(); - _d3d_device->DrawIndexedPrimitiveUP + draw_indexed_primitive_up (D3DPT_TRIANGLESTRIP, - min, max - min + 1, + min, max, ends[i] - start - 2, vertices + start * index_stride, index_type, array_data, stride); @@ -1138,9 +1139,9 @@ draw_trifans(const GeomTrifans *primitive) { _vertices_trifan_pcollector.add_level(ends[i] - start); unsigned int min = mins.get_data1i(); unsigned int max = maxs.get_data1i(); - _d3d_device->DrawIndexedPrimitiveUP + draw_indexed_primitive_up (D3DPT_TRIANGLEFAN, - min, max - min + 1, + min, max, ends[i] - start - 2, vertices + start * index_stride, index_type, array_data, stride); @@ -1211,9 +1212,9 @@ draw_lines(const GeomLines *primitive) { // Indexed, client arrays. D3DFORMAT index_type = get_index_type(primitive->get_index_type()); - _d3d_device->DrawIndexedPrimitiveUP + draw_indexed_primitive_up (D3DPT_LINELIST, - min_vertex, max_vertex - min_vertex + 1, + min_vertex, max_vertex, primitive->get_num_primitives(), primitive->get_data(), index_type, @@ -3525,7 +3526,7 @@ copy_pres_reset(DXScreenData *screen) { //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian8::get_d3d_min_type -// Access: Public, Static +// Access: Protected, Static // Description: //////////////////////////////////////////////////////////////////// D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian8:: @@ -3557,7 +3558,7 @@ get_d3d_min_type(Texture::FilterType filter_type) { //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian8::get_d3d_mip_type -// Access: Public, Static +// Access: Protected, Static // Description: //////////////////////////////////////////////////////////////////// D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian8:: @@ -3589,7 +3590,7 @@ get_d3d_mip_type(Texture::FilterType filter_type) { //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian8::get_texture_operation -// Access: Public, Static +// Access: Protected, Static // Description: Returns the D3DTEXTUREOP value corresponding to the // indicated TextureStage::CombineMode enumerated type. //////////////////////////////////////////////////////////////////// @@ -3637,7 +3638,7 @@ get_texture_operation(TextureStage::CombineMode mode, int scale) { //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian8::get_texture_argument -// Access: Public, Static +// Access: Protected, Static // Description: Returns the D3DTA value corresponding to the // indicated TextureStage::CombineSource and // TextureStage::CombineOperand enumerated types. @@ -3670,7 +3671,7 @@ get_texture_argument(TextureStage::CombineSource source, //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian8::get_texture_argument_modifier -// Access: Public, Static +// Access: Protected, Static // Description: Returns the extra bits that modify the D3DTA // argument, according to the indicated // TextureStage::CombineOperand enumerated type. @@ -3700,7 +3701,7 @@ get_texture_argument_modifier(TextureStage::CombineOperand operand) { //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian8::draw_primitive_up -// Access: Public +// Access: Protected // Description: Issues the DrawPrimitiveUP call to draw the indicated // primitive_type from the given buffer. We add the // num_vertices parameter, so we can determine the size @@ -3721,14 +3722,14 @@ draw_primitive_up(D3DPRIMITIVETYPE primitive_type, const unsigned char *buffer_start = buffer + stride * first_vertex; const unsigned char *buffer_end = buffer_start + stride * num_vertices; - + if (buffer_end - buffer_start > 0x10000) { // Actually, the buffer doesn't fit within the required limit // anyway. Go ahead and draw it and hope for the best. _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count, buffer_start, stride); - } else if ((((long)buffer_end ^ (long)buffer_start) & 0xffff) == 0) { + } else if ((((long)buffer_end ^ (long)buffer_start) & ~0xffff) == 0) { // No problem; we can draw the buffer directly. _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count, buffer_start, stride); @@ -3737,16 +3738,7 @@ draw_primitive_up(D3DPRIMITIVETYPE primitive_type, // We have a problem--the buffer crosses over a 0x10000 boundary. // We have to copy the buffer to a temporary buffer that we can // draw from. - static unsigned char *temp_buffer = NULL; - static unsigned char *safe_buffer_start = NULL; - if (temp_buffer == NULL) { - // Guarantee we get a buffer of size 0x10000 bytes that begins - // on an even multiple of 0x10000. We do this by allocating - // double the required buffer, and then pointing to the first - // multiple of 0x10000 within that buffer. - temp_buffer = new unsigned char[0x1ffff]; - safe_buffer_start = (unsigned char *)(((long)temp_buffer + 0xffff) & ~0xffff); - } + unsigned char *safe_buffer_start = get_safe_buffer_start(); memcpy(safe_buffer_start, buffer_start, buffer_end - buffer_start); _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count, safe_buffer_start, stride); @@ -3754,3 +3746,50 @@ draw_primitive_up(D3DPRIMITIVETYPE primitive_type, } } +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian8::draw_indexed_primitive_up +// Access: Protected +// Description: Issues the DrawIndexedPrimitiveUP call to draw the +// indicated primitive_type from the given buffer. As +// in draw_primitive_up(), above, the parameter list is +// not exactly one-for-one with the +// DrawIndexedPrimitiveUP() call, but it's similar (in +// particular, we pass max_index instead of NumVertices, +// which always seemed ambiguous to me). +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian8:: +draw_indexed_primitive_up(D3DPRIMITIVETYPE primitive_type, + unsigned int min_index, unsigned int max_index, + unsigned int num_primitives, + const unsigned char *index_data, + D3DFORMAT index_type, + const unsigned char *buffer, size_t stride) { + // As above, we'll hack the case of the buffer crossing the 0x10000 + // boundary. + const unsigned char *buffer_start = buffer + stride * min_index; + const unsigned char *buffer_end = buffer_start + stride * (max_index + 1); + + if (buffer_end - buffer_start > 0x10000) { + // Actually, the buffer doesn't fit within the required limit + // anyway. Go ahead and draw it and hope for the best. + _d3d_device->DrawIndexedPrimitiveUP + (primitive_type, min_index, max_index - min_index + 1, num_primitives, + index_data, index_type, buffer, stride); + + } else if ((((long)buffer_end ^ (long)buffer_start) & ~0xffff) == 0) { + // No problem; we can draw the buffer directly. + _d3d_device->DrawIndexedPrimitiveUP + (primitive_type, min_index, max_index - min_index + 1, num_primitives, + index_data, index_type, buffer, stride); + + } else { + // We have a problem--the buffer crosses over a 0x10000 boundary. + // We have to copy the buffer to a temporary buffer that we can + // draw from. + unsigned char *safe_buffer_start = get_safe_buffer_start(); + memcpy(safe_buffer_start, buffer_start, buffer_end - buffer_start); + _d3d_device->DrawIndexedPrimitiveUP + (primitive_type, min_index, max_index - min_index + 1, num_primitives, + index_data, index_type, safe_buffer_start - stride * min_index, stride); + } +} diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h index d3ce480d21..799acb6f31 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h @@ -177,6 +177,14 @@ protected: unsigned int first_vertex, unsigned int num_vertices, const unsigned char *buffer, size_t stride); + void draw_indexed_primitive_up(D3DPRIMITIVETYPE primitive_type, + unsigned int min_index, unsigned int max_index, + unsigned int num_primitives, + const unsigned char *index_data, + D3DFORMAT index_type, + const unsigned char *buffer, size_t stride); + + INLINE static unsigned char *get_safe_buffer_start(); protected: DXScreenData *_screen; @@ -223,6 +231,9 @@ protected: static D3DMATRIX _d3d_ident_mat; + static unsigned char *_temp_buffer; + static unsigned char *_safe_buffer_start; + public: virtual TypeHandle get_type() const { return get_class_type();