From c1a2458f8e2b15dc922b6f31b4fdb0106b204fb9 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 28 Jan 2026 16:10:24 +0100 Subject: [PATCH] tinydisplay: Fix assorted depth-related issues: - M_always depth test wasn't implemented but M_none was - framebuffer_copy_to_ram didn't work for the depth buffer - the clear depth value was being ignored - depth range on DisplayRegion wasn't being honored --- .../tinydisplay/tinyGraphicsStateGuardian.cxx | 112 +++++++++++++----- panda/src/tinydisplay/zbuffer.cxx | 2 +- 2 files changed, 81 insertions(+), 33 deletions(-) diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx index a260b23b2d..1c4c30d67f 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -229,10 +229,9 @@ clear(DrawableRegion *clearable) { } bool clear_z = false; - int z = 0; + ZPOINT z = 0; if (clearable->get_clear_depth_active()) { - // We ignore the specified depth clear value, since we don't support - // alternate depth compare functions anyway. + z = (ZPOINT)((1.0f - clearable->get_clear_depth()) * (1 << ZB_Z_BITS)); clear_z = true; } @@ -280,6 +279,18 @@ prepare_display_region(DisplayRegionPipelineReader *dr) { _c->viewport.ysize = ysize; set_scissor(0.0f, 1.0f, 0.0f, 1.0f); + PN_stdfloat dr_near = 0.0f; + PN_stdfloat dr_far = 1.0f; + dr->get_depth_range(dr_near, dr_far); + + if (dr_near == 0.0f && dr_far == 1.0f) { + _c->has_zrange = false; + } else { + _c->has_zrange = true; + _c->zmin = dr_near; + _c->zrange = dr_far - dr_near; + } + nassertv(xmin >= 0 && xmin < _c->zb->xsize && ymin >= 0 && ymin < _c->zb->ysize && xmin + xsize >= 0 && xmin + xsize <= _c->zb->xsize && @@ -875,7 +886,8 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, int depth_test_state = 1; // zless _c->depth_test = 1; // set this for ZB_line const DepthTestAttrib *target_depth_test = DCAST(DepthTestAttrib, _target_rs->get_attrib_def(DepthTestAttrib::get_class_slot())); - if (target_depth_test->get_mode() == DepthTestAttrib::M_none) { + if (target_depth_test->get_mode() == DepthTestAttrib::M_none || + target_depth_test->get_mode() == DepthTestAttrib::M_always) { depth_test_state = 0; // zless _c->depth_test = 0; } @@ -1415,10 +1427,17 @@ framebuffer_copy_to_ram(Texture *tex, int view, int z, z_size = 1; } - Texture::ComponentType component_type = Texture::T_unsigned_byte; - Texture::Format format = Texture::F_rgba; - if (_current_properties->get_srgb_color()) { - format = Texture::F_srgb_alpha; + Texture::ComponentType component_type; + Texture::Format format; + if (rb._buffer_type & RenderBuffer::T_depth) { + component_type = Texture::T_unsigned_int; + format = Texture::F_depth_component; + } else { + component_type = Texture::T_unsigned_byte; + format = Texture::F_rgba; + if (_current_properties->get_srgb_color()) { + format = Texture::F_srgb_alpha; + } } if (tex->get_x_size() != w || tex->get_y_size() != h || @@ -1445,32 +1464,53 @@ framebuffer_copy_to_ram(Texture *tex, int view, int z, } } - PIXEL *ip = (PIXEL *)(image_ptr + image_size); - PIXEL *fo = _c->zb->pbuf + xo + yo * _c->zb->linesize / PSZB; - for (int y = 0; y < h; ++y) { - ip -= w; -#ifndef WORDS_BIGENDIAN - // On a little-endian machine, we can copy the whole row at a time. - memcpy(ip, fo, w * PSZB); -#else - // On a big-endian machine, we have to reverse the color-component order. - const char *source = (const char *)fo; - const char *stop = (const char *)fo + w * PSZB; - char *dest = (char *)ip; - while (source < stop) { - char b = source[0]; - char g = source[1]; - char r = source[2]; - char a = source[3]; - dest[0] = a; - dest[1] = r; - dest[2] = g; - dest[3] = b; - dest += 4; - source += 4; + if (rb._buffer_type & RenderBuffer::T_depth) { + size_t dst_stride = tex->get_x_size(); + unsigned int *dst = (unsigned int *)(image_ptr + image_size); + size_t src_stride = _c->zb->xsize; + ZPOINT *src = _c->zb->zbuf + xo + src_stride * yo; + + for (int y = 0; y < h; ++y) { + dst -= dst_stride; + for (int x = 0; x < w; ++x) { + ZPOINT z = src[x]; + if (z == 0) { + z = 0xFFFFFFFF; + } else { + z = (1 << ZB_Z_BITS) - z; + z = z << (32 - ZB_Z_BITS); + } + dst[x] = z; + } } + } else { + PIXEL *ip = (PIXEL *)(image_ptr + image_size); + PIXEL *fo = _c->zb->pbuf + xo + yo * _c->zb->linesize / PSZB; + for (int y = 0; y < h; ++y) { + ip -= w; +#ifndef WORDS_BIGENDIAN + // On a little-endian machine, we can copy the whole row at a time. + memcpy(ip, fo, w * PSZB); +#else + // On a big-endian machine, we have to reverse the color-component order. + const char *source = (const char *)fo; + const char *stop = (const char *)fo + w * PSZB; + char *dest = (char *)ip; + while (source < stop) { + char b = source[0]; + char g = source[1]; + char r = source[2]; + char a = source[3]; + dest[0] = a; + dest[1] = r; + dest[2] = g; + dest[3] = b; + dest += 4; + source += 4; + } #endif - fo += _c->zb->linesize / PSZB; + fo += _c->zb->linesize / PSZB; + } } if (request != nullptr) { @@ -2075,8 +2115,16 @@ do_issue_depth_offset() { int offset = target_depth_offset->get_offset(); _c->zbias = offset; + PN_stdfloat dr_near = 0.0f; + PN_stdfloat dr_far = 1.0f; + if (_current_display_region != nullptr) { + _current_display_region->get_depth_range(dr_near, dr_far); + } + PN_stdfloat min_value = target_depth_offset->get_min_value(); PN_stdfloat max_value = target_depth_offset->get_max_value(); + min_value = dr_far * min_value + dr_near * (1 - min_value); + max_value = dr_far * max_value + dr_near * (1 - max_value); if (min_value == 0.0f && max_value == 1.0f) { _c->has_zrange = false; } else { diff --git a/panda/src/tinydisplay/zbuffer.cxx b/panda/src/tinydisplay/zbuffer.cxx index ceab7790d8..21ac68aaeb 100644 --- a/panda/src/tinydisplay/zbuffer.cxx +++ b/panda/src/tinydisplay/zbuffer.cxx @@ -420,7 +420,7 @@ ZB_clear_viewport(ZBuffer * zb, int clear_z, ZPOINT z, int clear_color, PIXEL co if (clear_z) { zz = zb->zbuf + xmin + ymin * zb->xsize; for (y = 0; y < ysize; ++y) { - memset(zz, 0, xsize * sizeof(ZPOINT)); + memset_l(zz, z, xsize); zz += zb->xsize; } }