From bac2073b7606e37d4e09c2ce920e6d24f4273c08 Mon Sep 17 00:00:00 2001 From: bkaradzic Date: Sat, 27 Jul 2013 15:27:54 -0700 Subject: [PATCH] Added support for per primitive scissor. --- examples/common/imgui/imgui.cpp | 8 +++-- include/bgfx.h | 5 +-- src/bgfx_p.h | 42 ++++++++++++++++++++++--- src/config.h | 4 +++ src/renderer_d3d11.cpp | 56 +++++++++++++++++++++++---------- src/renderer_d3d9.cpp | 43 ++++++++++++++++++------- src/renderer_gl.cpp | 41 +++++++++++++++++------- 7 files changed, 151 insertions(+), 48 deletions(-) diff --git a/examples/common/imgui/imgui.cpp b/examples/common/imgui/imgui.cpp index b10885096..76e7f1b1e 100644 --- a/examples/common/imgui/imgui.cpp +++ b/examples/common/imgui/imgui.cpp @@ -130,6 +130,7 @@ struct Imgui , m_insideCurrentScroll(false) , m_areaId(0) , m_widgetId(0) + , m_scissor(UINT16_MAX) , m_scrollTop(0) , m_scrollBottom(0) , m_scrollRight(0) @@ -403,7 +404,7 @@ struct Imgui , imguiRGBA(255, 255, 255, 128) ); -// setScissor(_x + SCROLL_AREA_PADDING, _y + SCROLL_AREA_PADDING, _width - SCROLL_AREA_PADDING * 4, _height - AREA_HEADER - SCROLL_AREA_PADDING); + m_scissor = bgfx::setScissor(_x + SCROLL_AREA_PADDING, _y + SCROLL_AREA_PADDING, _width - SCROLL_AREA_PADDING * 4, _height - AREA_HEADER - SCROLL_AREA_PADDING); return m_insideScrollArea; } @@ -411,7 +412,7 @@ struct Imgui void endScrollArea() { // Disable scissoring. -// setScissor(-1, -1, -1, -1); + m_scissor = UINT16_MAX; // Draw scroll bar int32_t xx = m_scrollRight + SCROLL_AREA_PADDING / 2; @@ -1066,6 +1067,7 @@ struct Imgui | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); bgfx::setProgram(m_colorProgram); + bgfx::setScissor(m_scissor); bgfx::submit(m_view); } } @@ -1354,6 +1356,7 @@ struct Imgui | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); bgfx::setProgram(m_textureProgram); + bgfx::setScissor(m_scissor); bgfx::submit(m_view); } } @@ -1380,6 +1383,7 @@ struct Imgui uint32_t m_areaId; uint32_t m_widgetId; + uint16_t m_scissor; float m_tempCoords[MAX_TEMP_COORDS * 2]; float m_tempNormals[MAX_TEMP_COORDS * 2]; diff --git a/include/bgfx.h b/include/bgfx.h index f069700b7..0c42b6b8d 100644 --- a/include/bgfx.h +++ b/include/bgfx.h @@ -853,9 +853,10 @@ namespace bgfx /// Set scissor from cache for draw primitive. /// - /// @param _cache Index in scissor cache. + /// @param _cache Index in scissor cache. Passing UINT16_MAX unset primitive + /// scissor and primitive will use view scissor instead. /// - void setScissor(uint16_t _cache); + void setScissor(uint16_t _cache = UINT16_MAX); /// Set model matrix for draw primitive. If it is not called model will /// be rendered with identity model matrix. diff --git a/src/bgfx_p.h b/src/bgfx_p.h index 307e279ef..f94d1fbb7 100755 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -651,6 +651,38 @@ namespace bgfx uint32_t m_num; }; + struct RectCache + { + RectCache() + : m_num(0) + { + } + + void reset() + { + m_num = 0; + } + + uint32_t add(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height) + { + BX_CHECK(m_num+1 < BGFX_CONFIG_MAX_RECT_CACHE, "Rect cache overflow. %d (max: %d)", m_num, BGFX_CONFIG_MAX_RECT_CACHE); + + uint32_t first = m_num; + Rect& rect = m_cache[m_num]; + + rect.m_x = _x; + rect.m_y = _y; + rect.m_width = _width; + rect.m_height = _height; + + m_num++; + return first; + } + + Rect m_cache[BGFX_CONFIG_MAX_RECT_CACHE]; + uint32_t m_num; + }; + struct Sampler { uint32_t m_flags; @@ -860,7 +892,7 @@ namespace bgfx m_instanceDataStride = 0; m_numInstances = 1; m_num = 1; - m_scissor = 0; + m_scissor = UINT16_MAX; m_vertexBuffer.idx = invalidHandle; m_vertexDecl.idx = invalidHandle; m_indexBuffer.idx = invalidHandle; @@ -958,6 +990,7 @@ namespace bgfx { m_state.reset(); m_matrixCache.reset(); + m_rectCache.reset(); m_key.reset(); m_num = 0; m_numRenderStates = 0; @@ -1008,9 +1041,9 @@ namespace bgfx uint16_t setScissor(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height) { - BX_UNUSED(_x, _y, _width, _height); - m_state.m_scissor = 0; - return 0; + uint16_t scissor = m_rectCache.add(_x, _y, _width, _height); + m_state.m_scissor = scissor; + return scissor; } void setScissor(uint16_t _cache) @@ -1256,6 +1289,7 @@ namespace bgfx uint16_t m_numDropped; MatrixCache m_matrixCache; + RectCache m_rectCache; uint32_t m_iboffset; uint32_t m_vboffset; diff --git a/src/config.h b/src/config.h index 6857735a6..4035348a2 100644 --- a/src/config.h +++ b/src/config.h @@ -127,6 +127,10 @@ # define BGFX_CONFIG_MAX_MATRIX_CACHE (16<<10) #endif // BGFX_CONFIG_MAX_MATRIX_CACHE +#ifndef BGFX_CONFIG_MAX_RECT_CACHE +# define BGFX_CONFIG_MAX_RECT_CACHE 512 +#endif // BGFX_CONFIG_MAX_RECT_CACHE + #ifndef BGFX_CONFIG_MAX_VIEWS # define BGFX_CONFIG_MAX_VIEWS 32 #endif // BGFX_CONFIG_MAX_VIEWS diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index eb468660f..e6c1592f2 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -2314,7 +2314,7 @@ namespace bgfx } bool wireframe = !!(m_render->m_debug&BGFX_DEBUG_WIREFRAME); - bool scissor = false; + bool scissorEnabled = false; s_renderCtx.setDebugWireframe(wireframe); uint16_t programIdx = invalidHandle; @@ -2349,6 +2349,7 @@ namespace bgfx if (key.m_view != view) { currentState.clear(); + currentState.m_scissor = !state.m_scissor; changedFlags = BGFX_STATE_MASK; changedStencil = packStencil(BGFX_STENCIL_MASK, BGFX_STENCIL_MASK); currentState.m_flags = newFlags; @@ -2383,21 +2384,8 @@ namespace bgfx m_clearQuad.clear(rect, clear); } - Rect& scissorRect = m_render->m_scissor[view]; - scissor = !scissorRect.isZero(); - if (scissor) - { - D3D11_RECT rc; - rc.left = scissorRect.m_x; - rc.top = scissorRect.m_y; - rc.right = scissorRect.m_x + scissorRect.m_width; - rc.bottom = scissorRect.m_y + scissorRect.m_height; - deviceCtx->RSSetScissorRects(1, &rc); - } - - s_renderCtx.setBlendState(BGFX_STATE_DEFAULT); - s_renderCtx.setDepthStencilState(BGFX_STATE_DEFAULT, packStencil(BGFX_STENCIL_DEFAULT, BGFX_STENCIL_DEFAULT) ); - s_renderCtx.setRasterizerState(BGFX_STATE_DEFAULT, wireframe, scissor); + s_renderCtx.setBlendState(newFlags); + s_renderCtx.setDepthStencilState(newFlags, packStencil(BGFX_STENCIL_DEFAULT, BGFX_STENCIL_DEFAULT) ); uint8_t primIndex = uint8_t( (newFlags&BGFX_STATE_PT_MASK)>>BGFX_STATE_PT_SHIFT); if (primType != s_primType[primIndex]) @@ -2408,6 +2396,40 @@ namespace bgfx } } + uint16_t scissor = state.m_scissor; + if (currentState.m_scissor != scissor) + { + currentState.m_scissor = scissor; + + if (UINT16_MAX == scissor) + { + const Rect& scissorRect = m_render->m_scissor[view]; + scissorEnabled = !scissorRect.isZero(); + if (scissorEnabled) + { + D3D11_RECT rc; + rc.left = scissorRect.m_x; + rc.top = scissorRect.m_y; + rc.right = scissorRect.m_x + scissorRect.m_width; + rc.bottom = scissorRect.m_y + scissorRect.m_height; + deviceCtx->RSSetScissorRects(1, &rc); + } + } + else + { + const Rect& scissorRect = m_render->m_rectCache.m_cache[scissor]; + scissorEnabled = true; + D3D11_RECT rc; + rc.left = scissorRect.m_x; + rc.top = scissorRect.m_y; + rc.right = scissorRect.m_x + scissorRect.m_width; + rc.bottom = scissorRect.m_y + scissorRect.m_height; + deviceCtx->RSSetScissorRects(1, &rc); + } + + s_renderCtx.setRasterizerState(newFlags, wireframe, scissorEnabled); + } + if ( (BGFX_STATE_DEPTH_WRITE|BGFX_STATE_DEPTH_TEST_MASK) & changedFlags || 0 != changedStencil) { @@ -2433,7 +2455,7 @@ namespace bgfx if ( (BGFX_STATE_CULL_MASK|BGFX_STATE_MSAA) & changedFlags) { - s_renderCtx.setRasterizerState(newFlags, wireframe, scissor); + s_renderCtx.setRasterizerState(newFlags, wireframe, scissorEnabled); } if (BGFX_STATE_ALPHA_REF_MASK & changedFlags) diff --git a/src/renderer_d3d9.cpp b/src/renderer_d3d9.cpp index 4f56b6e8c..6a886b940 100644 --- a/src/renderer_d3d9.cpp +++ b/src/renderer_d3d9.cpp @@ -2287,6 +2287,7 @@ namespace bgfx if (key.m_view != view) { currentState.clear(); + currentState.m_scissor = !state.m_scissor; changedFlags = BGFX_STATE_MASK; changedStencil = packStencil(BGFX_STENCIL_MASK, BGFX_STENCIL_MASK); currentState.m_flags = newFlags; @@ -2354,11 +2355,38 @@ namespace bgfx } } - Rect& scissorRect = m_render->m_scissor[view]; - bool scissor = !scissorRect.isZero(); - DX_CHECK(device->SetRenderState(D3DRS_SCISSORTESTENABLE, scissor) ); - if (scissor) + DX_CHECK(device->SetRenderState(D3DRS_STENCILENABLE, FALSE) ); + DX_CHECK(device->SetRenderState(D3DRS_ZENABLE, TRUE) ); + DX_CHECK(device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS) ); + DX_CHECK(device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE) ); + DX_CHECK(device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE) ); + DX_CHECK(device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER) ); + } + + uint16_t scissor = state.m_scissor; + if (currentState.m_scissor != scissor) + { + currentState.m_scissor = scissor; + + if (UINT16_MAX == scissor) { + const Rect& scissorRect = m_render->m_scissor[view]; + bool scissorEnabled = !scissorRect.isZero(); + DX_CHECK(device->SetRenderState(D3DRS_SCISSORTESTENABLE, scissorEnabled) ); + if (scissorEnabled) + { + RECT rc; + rc.left = scissorRect.m_x; + rc.top = scissorRect.m_y; + rc.right = scissorRect.m_x + scissorRect.m_width; + rc.bottom = scissorRect.m_y + scissorRect.m_height; + DX_CHECK(device->SetScissorRect(&rc) ); + } + } + else + { + DX_CHECK(device->SetRenderState(D3DRS_SCISSORTESTENABLE, true) ); + const Rect& scissorRect = m_render->m_rectCache.m_cache[scissor]; RECT rc; rc.left = scissorRect.m_x; rc.top = scissorRect.m_y; @@ -2366,13 +2394,6 @@ namespace bgfx rc.bottom = scissorRect.m_y + scissorRect.m_height; DX_CHECK(device->SetScissorRect(&rc) ); } - - DX_CHECK(device->SetRenderState(D3DRS_STENCILENABLE, FALSE) ); - DX_CHECK(device->SetRenderState(D3DRS_ZENABLE, TRUE) ); - DX_CHECK(device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS) ); - DX_CHECK(device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE) ); - DX_CHECK(device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE) ); - DX_CHECK(device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER) ); } if (0 != changedStencil) diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 2b1adc3cb..2ee5ad58c 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -2836,9 +2836,11 @@ namespace bgfx if (key.m_view != view) { currentState.clear(); + currentState.m_scissor = !state.m_scissor; changedFlags = BGFX_STATE_MASK; changedStencil = packStencil(BGFX_STENCIL_MASK, BGFX_STENCIL_MASK); currentState.m_flags = newFlags; + currentState.m_stencil = newStencil; GREMEDY_SETMARKER(s_viewName[key.m_view]); @@ -2862,18 +2864,6 @@ namespace bgfx m_clearQuad.clear(rect, clear, height); } - Rect& scissorRect = m_render->m_scissor[view]; - bool scissor = !scissorRect.isZero(); - if (scissor) - { - GL_CHECK(glEnable(GL_SCISSOR_TEST) ); - GL_CHECK(glScissor(scissorRect.m_x, height-scissorRect.m_height-scissorRect.m_y, scissorRect.m_width, scissorRect.m_height) ); - } - else - { - GL_CHECK(glDisable(GL_SCISSOR_TEST) ); - } - GL_CHECK(glDisable(GL_STENCIL_TEST) ); GL_CHECK(glEnable(GL_DEPTH_TEST) ); GL_CHECK(glDepthFunc(GL_LESS) ); @@ -2881,6 +2871,33 @@ namespace bgfx GL_CHECK(glDisable(GL_BLEND) ); } + uint16_t scissor = state.m_scissor; + if (currentState.m_scissor != scissor) + { + currentState.m_scissor = scissor; + + if (UINT16_MAX == scissor) + { + const Rect& scissorRect = m_render->m_scissor[view]; + bool scissor = !scissorRect.isZero(); + if (scissor) + { + GL_CHECK(glEnable(GL_SCISSOR_TEST) ); + GL_CHECK(glScissor(scissorRect.m_x, height-scissorRect.m_height-scissorRect.m_y, scissorRect.m_width, scissorRect.m_height) ); + } + else + { + GL_CHECK(glDisable(GL_SCISSOR_TEST) ); + } + } + else + { + const Rect& scissorRect = m_render->m_rectCache.m_cache[scissor]; + GL_CHECK(glEnable(GL_SCISSOR_TEST) ); + GL_CHECK(glScissor(scissorRect.m_x, height-scissorRect.m_height-scissorRect.m_y, scissorRect.m_width, scissorRect.m_height) ); + } + } + if (0 != changedStencil) { if (0 != newStencil)