diff --git a/src/glimports.h b/src/glimports.h index fc1cebed1..131e6bb29 100644 --- a/src/glimports.h +++ b/src/glimports.h @@ -68,6 +68,8 @@ typedef void (GL_APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GL typedef void (GL_APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GL_APIENTRYP PFNGLCLEARDEPTHPROC) (GLdouble d); typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); +typedef void (GL_APIENTRYP PFNGLDEPTHRANGEPROC) (GLdouble n, GLdouble f); +typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); typedef void (GL_APIENTRYP PFNGLCLEARSTENCILPROC) (GLint s); typedef void (GL_APIENTRYP PFNGLCLIPCONTROLPROC) (GLenum origin, GLenum depth); typedef void (GL_APIENTRYP PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); @@ -454,6 +456,7 @@ GL_IMPORT______(false, PFNGLVIEWPORTPROC, glViewport); # if BGFX_CONFIG_RENDERER_OPENGL GL_IMPORT______(false, PFNGLCLEARDEPTHPROC, glClearDepth); +GL_IMPORT______(false, PFNGLDEPTHRANGEPROC, glDepthRange); GL_IMPORT______(true, PFNGLPOINTSIZEPROC, glPointSize); GL_IMPORT______(true, PFNGLPOLYGONMODEPROC, glPolygonMode); @@ -508,6 +511,7 @@ GL_IMPORT______(true, PFNGLTEXIMAGE3DMULTISAMPLEPROC, glTexImage3DM # else // GLES GL_IMPORT______(false, PFNGLCLEARDEPTHFPROC, glClearDepthf); +GL_IMPORT______(false, PFNGLDEPTHRANGEFPROC, glDepthRangef); GL_IMPORT_EXT__(true, PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample); # endif // BGFX_CONFIG_RENDERER_OPENGL diff --git a/src/renderer.h b/src/renderer.h index 782d02475..19af62365 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -7,6 +7,7 @@ #define BGFX_RENDERER_H_HEADER_GUARD #include "bgfx_p.h" +#include namespace bgfx { @@ -15,6 +16,51 @@ namespace bgfx bx::memCopy(&_viewName[4], _str.getPtr(), _str.getLength() ); } + inline bool isIntegerFormat(TextureFormat::Enum _format) + { + const bx::EncodingType::Enum encoding = bx::EncodingType::Enum(bimg::getBlockInfo(bimg::TextureFormat::Enum(_format) ).encoding); + return bx::EncodingType::Int == encoding + || bx::EncodingType::Uint == encoding + ; + } + + inline void getClearColor(float _rgba[4], const Clear& _clear, const float _palette[][4], uint32_t _attachment, bool _integer) + { + if (BGFX_CLEAR_COLOR_USE_PALETTE & _clear.m_flags) + { + const uint8_t index = bx::min(BGFX_CONFIG_MAX_COLOR_PALETTE-1, _clear.m_index[_attachment]); + bx::memCopy(_rgba, _palette[index], sizeof(float)*4); + } + else + { + const float scale = _integer ? 1.0f : 1.0f/255.0f; + _rgba[0] = _clear.m_index[0]*scale; + _rgba[1] = _clear.m_index[1]*scale; + _rgba[2] = _clear.m_index[2]*scale; + _rgba[3] = _clear.m_index[3]*scale; + } + } + + inline uint32_t packIntegerTexel(uint8_t* _out, TextureFormat::Enum _format, const float _rgba[4]) + { + const bimg::ImageBlockInfo& info = bimg::getBlockInfo(bimg::TextureFormat::Enum(_format) ); + const uint8_t bits[4] = { info.rBits, info.gBits, info.bBits, info.aBits }; + + uint32_t size = 0; + + for (uint32_t ii = 0; ii < 4; ++ii) + { + const int64_t value = int64_t(_rgba[ii]); + + for (uint32_t bb = 0, num = bits[ii]/8; bb < num; ++bb) + { + _out[size++] = uint8_t(value >> (bb*8) ); + } + } + + return size; + } + static constexpr uint32_t kTimerQueryBlock = 64; static constexpr uint32_t kMaxTimerQueries = BGFX_CONFIG_MAX_VIEWS*4; static constexpr uint32_t kMinTimerQueries = bx::min(kTimerQueryBlock, kMaxTimerQueries); diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index f6bc7fc3f..3f07c21d7 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -505,6 +505,7 @@ namespace bgfx { namespace d3d11 BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wunneeded-internal-declaration"); static const GUID IID_ID3D11Device1 = { 0xa04bfb29, 0x08ef, 0x43d6, { 0xa4, 0x9c, 0xa9, 0xbd, 0xbd, 0xcb, 0xe6, 0x86 } }; + static const GUID IID_ID3D11DeviceContext1 = { 0xbb2c6faa, 0xb5fb, 0x4082, { 0x8e, 0x6b, 0x38, 0x8b, 0x8c, 0xfa, 0x90, 0xe1 } }; static const GUID IID_ID3D11Device2 = { 0x9d06dffa, 0xd1e5, 0x4d07, { 0x83, 0xa8, 0x1b, 0xb1, 0x23, 0xf2, 0xf8, 0x41 } }; extern const GUID IID_ID3D11Device3 = { 0xa05c8c37, 0xd2c6, 0x4732, { 0xb3, 0xa0, 0x9c, 0xe0, 0xb0, 0xdc, 0x9a, 0xe6 } }; static const GUID IID_ID3D11InfoQueue = { 0x6543dbb6, 0x1b48, 0x42f5, { 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6 } }; @@ -800,6 +801,7 @@ namespace bgfx { namespace d3d11 , m_device(NULL) , m_deviceCtx(NULL) , m_annotation(NULL) + , m_deviceCtx1(NULL) , m_infoQueue(NULL) , m_deviceInterfaceVersion(0) , m_currentColor(NULL) @@ -1246,6 +1248,11 @@ namespace bgfx { namespace d3d11 m_numWindows = 1; + if (FAILED(m_deviceCtx->QueryInterface(IID_ID3D11DeviceContext1, (void**)&m_deviceCtx1) ) ) + { + m_deviceCtx1 = NULL; + } + #if USE_D3D11_DYNAMIC_LIB if (BX_ENABLED(BGFX_CONFIG_DEBUG_ANNOTATION) ) { @@ -1657,6 +1664,7 @@ namespace bgfx { namespace d3d11 { case ErrorState::LoadedDXGI: DX_RELEASE(m_annotation, 1); + DX_RELEASE_I(m_deviceCtx1); DX_RELEASE_W(m_infoQueue, 0); DX_RELEASE(mainFrameBuffer().m_msaaRt, 0); @@ -1750,6 +1758,7 @@ namespace bgfx { namespace d3d11 m_textures[ii].destroy(); } + DX_RELEASE_I(m_deviceCtx1); DX_RELEASE(m_annotation, 1); dumpInfoQueue(); DX_RELEASE_W(m_infoQueue, 0); @@ -3824,8 +3833,42 @@ namespace bgfx { namespace d3d11 { ID3D11DeviceContext* deviceCtx = m_deviceCtx; + bool clearColor = 0 != (_clear.m_flags & BGFX_CLEAR_COLOR); + + if (clearColor + && intColor + && NULL != m_deviceCtx1) + { + const FrameBufferD3D11& fb = m_frameBuffers[m_fbh.idx]; + const D3D11_RECT rect = { _rect.m_x, _rect.m_y, _rect.m_x + _rect.m_width, _rect.m_y + _rect.m_height }; + const uint8_t skipMask = _clear.getColorSkipMask(fb.m_num); + + for (uint32_t ii = 0; ii < fb.m_num; ++ii) + { + if (NULL == fb.m_rtv[ii] + || 0 != (skipMask & (1<ClearView(fb.m_rtv[ii], rgba, &rect, 1); + } + + if (0 == (_clear.m_flags & (BGFX_CLEAR_DEPTH|BGFX_CLEAR_STENCIL) ) ) + { + return; + } + + clearColor = false; + } + const uint64_t state = 0 - | (_clear.m_flags & BGFX_CLEAR_COLOR ? BGFX_STATE_WRITE_RGB|BGFX_STATE_WRITE_A : 0) + | (clearColor ? BGFX_STATE_WRITE_RGB|BGFX_STATE_WRITE_A : 0) | (_clear.m_flags & BGFX_CLEAR_DEPTH ? BGFX_STATE_DEPTH_TEST_ALWAYS|BGFX_STATE_WRITE_Z : 0) ; @@ -3862,7 +3905,8 @@ namespace bgfx { namespace d3d11 const float mrtClearDepth[4] = { _clear.m_depth }; deviceCtx->UpdateSubresource(vsh->m_buffer, 0, 0, mrtClearDepth, 0, 0); - if (NULL != m_currentColor) + if (clearColor + && NULL != m_currentColor) { const ShaderD3D11* fsh = program.m_fsh; deviceCtx->PSSetShader(fsh->m_pixelShader, NULL, 0); @@ -3973,6 +4017,7 @@ namespace bgfx { namespace d3d11 ID3D11Device* m_device; ID3D11DeviceContext* m_deviceCtx; ID3DUserDefinedAnnotation* m_annotation; + ID3D11DeviceContext1* m_deviceCtx1; ID3D11InfoQueue* m_infoQueue; TimerQueryD3D11 m_gpuTimer; diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 07f0f7a06..06d141dd6 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -4985,6 +4985,141 @@ namespace bgfx { namespace gl } else { + bool intMrt = false; + + if (isValid(fbh) + && NULL != glClearBufferfv + && NULL != glClearBufferiv + && NULL != glClearBufferuiv) + { + const FrameBufferGL& fb = m_frameBuffers[fbh.idx]; + + for (uint32_t ii = 0; ii < fb.m_numTh && !intMrt; ++ii) + { + const Attachment& at = fb.m_attachment[ii]; + + if (!isValid(at.handle) ) + { + continue; + } + + const TextureFormat::Enum format = TextureFormat::Enum(m_textures[at.handle.idx].m_textureFormat); + + if (bimg::isDepth(bimg::TextureFormat::Enum(format) ) ) + { + continue; + } + + const bx::EncodingType::Enum enc = bx::EncodingType::Enum(bimg::getBlockInfo(bimg::TextureFormat::Enum(format) ).encoding); + intMrt = bx::EncodingType::Int == enc + || bx::EncodingType::Uint == enc + ; + } + } + + if (intMrt) + { + const FrameBufferGL& fb = m_frameBuffers[fbh.idx]; + const bool usePalette = 0 != (BGFX_CLEAR_COLOR_USE_PALETTE & _clear.m_flags); + + GL_CHECK(glEnable(GL_SCISSOR_TEST) ); + GL_CHECK(glScissor(_rect.m_x, rectY, _rect.m_width, _rect.m_height) ); + GL_CHECK(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) ); + + if (BGFX_CLEAR_COLOR & _clear.m_flags) + { + GLint drawBuffer = 0; + + for (uint32_t ii = 0; ii < fb.m_numTh; ++ii) + { + const Attachment& at = fb.m_attachment[ii]; + + if (!isValid(at.handle) ) + { + continue; + } + + const TextureFormat::Enum format = TextureFormat::Enum(m_textures[at.handle.idx].m_textureFormat); + + if (bimg::isDepth(bimg::TextureFormat::Enum(format) ) ) + { + continue; + } + + const uint8_t index = usePalette ? _clear.m_index[drawBuffer] : 0; + + if (usePalette + && UINT8_MAX == index) + { + ++drawBuffer; + continue; + } + + const float* palette = usePalette + ? _palette[bx::min(BGFX_CONFIG_MAX_COLOR_PALETTE-1, index)] + : NULL + ; + + const bx::EncodingType::Enum enc = bx::EncodingType::Enum(bimg::getBlockInfo(bimg::TextureFormat::Enum(format) ).encoding); + + if (bx::EncodingType::Uint == enc + || bx::EncodingType::Int == enc) + { + GLint value[4]; + + for (uint32_t cc = 0; cc < 4; ++cc) + { + value[cc] = NULL != palette + ? GLint(palette[cc]) + : GLint(_clear.m_index[cc]) + ; + } + + if (bx::EncodingType::Uint == enc) + { + GL_CHECK(glClearBufferuiv(GL_COLOR, drawBuffer, (const GLuint*)value) ); + } + else + { + GL_CHECK(glClearBufferiv(GL_COLOR, drawBuffer, value) ); + } + } + else + { + float rgba[4]; + + for (uint32_t cc = 0; cc < 4; ++cc) + { + rgba[cc] = NULL != palette + ? palette[cc] + : _clear.m_index[cc]*1.0f/255.0f + ; + } + + GL_CHECK(glClearBufferfv(GL_COLOR, drawBuffer, rgba) ); + } + + ++drawBuffer; + } + } + + if (BGFX_CLEAR_DEPTH & _clear.m_flags) + { + GL_CHECK(glDepthMask(GL_TRUE) ); + GL_CHECK(glClearBufferfv(GL_DEPTH, 0, &_clear.m_depth) ); + } + + if (BGFX_CLEAR_STENCIL & _clear.m_flags) + { + const GLint stencil = _clear.m_stencil; + GL_CHECK(glStencilMask(0xff) ); + GL_CHECK(glClearBufferiv(GL_STENCIL, 0, &stencil) ); + } + + GL_CHECK(glDisable(GL_SCISSOR_TEST) ); + return; + } + if (0 != m_vao) { GL_CHECK(glBindVertexArray(m_vao) ); @@ -8821,6 +8956,13 @@ namespace bgfx { namespace gl float currentPolygonOffsetSlope = 0.0f; float currentPolygonOffsetClamp = 0.0f; + GL_CHECK(glDisable(GL_POLYGON_OFFSET_FILL) ); + + if (s_extension[Extension::ARB_depth_clamp].m_supported) + { + GL_CHECK(glDisable(GL_DEPTH_CLAMP) ); + } + UniformCacheState ucs(_render); BlitState bs(_render); @@ -8973,6 +9115,8 @@ namespace bgfx { namespace gl , viewState.m_rect.m_height ) ); + GL_CHECK(glDepthRange(0.0f, 1.0f) ); + const Clear& clear = renderView->m_clear; discardFlags = clear.m_flags & BGFX_CLEAR_DISCARD_MASK; @@ -8984,6 +9128,7 @@ namespace bgfx { namespace gl GL_CHECK(glDisable(GL_STENCIL_TEST) ); GL_CHECK(glEnable(GL_DEPTH_TEST) ); GL_CHECK(glDepthFunc(GL_LESS) ); + GL_CHECK(glDepthRange(renderView->m_minDepth, renderView->m_maxDepth) ); GL_CHECK(glEnable(GL_CULL_FACE) ); GL_CHECK(glDisable(GL_BLEND) ); } diff --git a/src/renderer_gl.h b/src/renderer_gl.h index 9ae2aed47..957f89bd5 100644 --- a/src/renderer_gl.h +++ b/src/renderer_gl.h @@ -1231,6 +1231,7 @@ typedef double GLdouble; #if !BGFX_CONFIG_RENDERER_OPENGL # define glClearDepth glClearDepthf +# define glDepthRange glDepthRangef #endif // !BGFX_CONFIG_RENDERER_OPENGL namespace bgfx diff --git a/src/renderer_mtl.cpp b/src/renderer_mtl.cpp index 0808cd31b..eb0ed4d6f 100644 --- a/src/renderer_mtl.cpp +++ b/src/renderer_mtl.cpp @@ -2358,6 +2358,91 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames } } + bool clearIntegerColor(FrameBufferHandle _fbh, const Rect& _rect, const Clear& _clear, const float _palette[][4]) + { + if (!isValid(_fbh) + || 0 == (_clear.m_flags & BGFX_CLEAR_COLOR) ) + { + return false; + } + + const FrameBufferMtl& fb = m_frameBuffers[_fbh.idx]; + + bool integer = false; + + for (uint32_t ii = 0; ii < fb.m_num; ++ii) + { + const TextureMtl& texture = m_textures[fb.m_colorHandle[ii].idx]; + integer |= NULL == texture.m_ptrMsaa + && isIntegerFormat(TextureFormat::Enum(texture.m_textureFormat) ) + ; + } + + if (!integer) + { + return false; + } + + const uint8_t skipMask = _clear.getColorSkipMask(fb.m_num); + + for (uint32_t ii = 0; ii < fb.m_num; ++ii) + { + if (0 != (skipMask & (1<newBuffer(size, MTL::ResourceStorageModeShared); + uint8_t* data = (uint8_t*)buffer->contents(); + + for (uint32_t xx = 0; xx < _rect.m_width; ++xx) + { + bx::memCopy(data + xx*texelSize, texel, texelSize); + } + + for (uint32_t yy = 1; yy < _rect.m_height; ++yy) + { + bx::memCopy(data + yy*pitch, data, pitch); + } + + MTL::BlitCommandEncoder* bce = getBlitCommandEncoder(); + bce->copyFromBuffer( + buffer + , 0 + , pitch + , size + , MTL::Size::Make(_rect.m_width, _rect.m_height, 1) + , texture.m_ptr + , 0 + , 0 + , MTL::Origin::Make(_rect.m_x, _rect.m_y, 0) + ); + + MTL_RELEASE_I(buffer); + } + + endBlitEncoding(); + + return true; + } + void clearQuad(const ClearQuad& _clearQuad, const Rect& /*_rect*/, const Clear& _clear, const float _palette[][4]) { const uint64_t state = 0 @@ -6258,6 +6343,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames const Rect viewRect = viewState.m_rect; bool clearWithRenderPass = false; + bool integerCleared = false; if (NULL == m_renderCommandEncoder || fbh.idx != renderView->m_fbh.idx @@ -6294,6 +6380,10 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames && height == viewRect.m_height ; + integerCleared = !clearWithRenderPass + && clearIntegerColor(fbh, clippedRect, clr, _render->m_colorPalette) + ; + setFrameBuffer(renderPassDescriptor, fbh); if (clearWithRenderPass) @@ -6437,30 +6527,33 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames rce->setTriangleFillMode( (MTL::TriangleFillMode)wireframe ? MTL::TriangleFillModeLines : MTL::TriangleFillModeFill); - { - MTL::Viewport vp; - vp.originX = viewState.m_rect.m_x; - vp.originY = viewState.m_rect.m_y; - vp.width = viewState.m_rect.m_width; - vp.height = viewState.m_rect.m_height; - vp.znear = 0.0f; - vp.zfar = 1.0f; - rce->setViewport(vp); + MTL::Viewport vp; + vp.originX = viewState.m_rect.m_x; + vp.originY = viewState.m_rect.m_y; + vp.width = viewState.m_rect.m_width; + vp.height = viewState.m_rect.m_height; + vp.znear = 0.0f; + vp.zfar = 1.0f; + rce->setViewport(vp); - MTL::ScissorRect sciRect = { - NS::UInteger(clippedRect.m_x), - NS::UInteger(clippedRect.m_y), - NS::UInteger(clippedRect.m_width), - NS::UInteger(clippedRect.m_height) - }; - rce->setScissorRect(sciRect); - } + MTL::ScissorRect sciRect = { + NS::UInteger(clippedRect.m_x), + NS::UInteger(clippedRect.m_y), + NS::UInteger(clippedRect.m_width), + NS::UInteger(clippedRect.m_height) + }; + rce->setScissorRect(sciRect); if (BGFX_CLEAR_NONE != (clr.m_flags & BGFX_CLEAR_MASK) - && !clearWithRenderPass) + && !clearWithRenderPass + && !integerCleared) { clearQuad(_clearQuad, clippedRect, clr, _render->m_colorPalette); } + + vp.znear = renderView->m_minDepth; + vp.zfar = renderView->m_maxDepth; + rce->setViewport(vp); } } diff --git a/src/renderer_webgpu.cpp b/src/renderer_webgpu.cpp index 1931f03ab..f5c62daf6 100644 --- a/src/renderer_webgpu.cpp +++ b/src/renderer_webgpu.cpp @@ -2495,6 +2495,105 @@ WGPU_IMPORT wgpuRelease(blitRenderPassEncoder); } + bool clearIntegerColor(WGPUCommandEncoder _commandEncoder, const FrameBufferWGPU& _fb, const Rect& _rect, const Clear& _clear, const float _palette[][4]) + { + if (0 == (_clear.m_flags & BGFX_CLEAR_COLOR) + || 1 < _fb.m_msaaCount) + { + return false; + } + + bool integer = false; + + for (uint32_t ii = 0; ii < _fb.m_numColorAttachments; ++ii) + { + const TextureWGPU& texture = m_textures[_fb.m_texture[ii].idx]; + integer |= isIntegerFormat(TextureFormat::Enum(texture.m_textureFormat) ); + } + + if (!integer) + { + return false; + } + + const uint8_t skipMask = _clear.getColorSkipMask(_fb.m_numColorAttachments); + + for (uint32_t ii = 0; ii < _fb.m_numColorAttachments; ++ii) + { + if (0 != (skipMask & (1<m_colorPalette) + ; + renderPassEncoder = WGPU_CHECK(wgpuCommandEncoderBeginRenderPass(cmdEncoder, &renderPassDesc) ); currentPipeline = NULL; @@ -7254,11 +7361,23 @@ WGPU_IMPORT , 1.0f ); - if (!clearWhole && needClear) + if (!clearWhole + && needClear + && !integerCleared) { clearQuad(renderPassEncoder, fbh, msaaCount, _clearQuad, clippedRect, clr, _render->m_colorPalette); } + wgpuRenderPassEncoderSetViewport( + renderPassEncoder + , float(viewRect.m_x) + , float(viewRect.m_y) + , float(viewRect.m_width) + , float(viewRect.m_height) + , renderView->m_minDepth + , renderView->m_maxDepth + ); + wgpuRenderPassEncoderSetScissorRect( renderPassEncoder , uint32_t(viewScissorRect.m_x)