| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674 |
- // Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include "anki/gr/CommandBufferHandle.h"
- #include "anki/gr/GlDevice.h"
- #include "anki/gr/gl/FramebufferImpl.h"
- #include "anki/gr/TextureHandle.h"
- #include "anki/gr/gl/TextureImpl.h"
- #include "anki/gr/BufferHandle.h"
- #include "anki/gr/gl/BufferImpl.h"
- #include "anki/gr/OcclusionQueryHandle.h"
- #include "anki/gr/gl/OcclusionQueryImpl.h"
- #include "anki/core/Counters.h"
- #include <utility>
- namespace anki {
- //==============================================================================
- // Macros because we are bored to type
- #define ANKI_STATE_CMD_0(type_, glfunc_) \
- class Command: public GlCommand \
- { \
- public: \
- Command() = default \
- Error operator()(CommandBufferImpl*) \
- { \
- glfunc_(); \
- return ErrorCode::NONE; \
- } \
- }; \
- _pushBackNewCommand<Command>(value_)
- #define ANKI_STATE_CMD_1(type_, glfunc_, value_) \
- class Command: public GlCommand \
- { \
- public: \
- type_ m_value; \
- Command(type_ v) \
- : m_value(v) \
- {} \
- Error operator()(CommandBufferImpl*) \
- { \
- glfunc_(m_value); \
- return ErrorCode::NONE; \
- } \
- }; \
- _pushBackNewCommand<Command>(value_)
- #define ANKI_STATE_CMD_2(type_, glfunc_, a_, b_) \
- class Command: public GlCommand \
- { \
- public: \
- Array<type_, 2> m_value; \
- Command(type_ a, type_ b) \
- { \
- m_value = {{a, b}}; \
- } \
- Error operator()(CommandBufferImpl*) \
- { \
- glfunc_(m_value[0], m_value[1]); \
- return ErrorCode::NONE; \
- } \
- }; \
- _pushBackNewCommand<Command>(a_, b_)
- #define ANKI_STATE_CMD_3(type_, glfunc_, a_, b_, c_) \
- class Command: public GlCommand \
- { \
- public: \
- Array<type_, 3> m_value; \
- Command(type_ a, type_ b, type_ c) \
- { \
- m_value = {{a, b, c}}; \
- } \
- Error operator()(CommandBufferImpl*) \
- { \
- glfunc_(m_value[0], m_value[1], m_value[2]); \
- return ErrorCode::NONE; \
- } \
- }; \
- _pushBackNewCommand<Command>(a_, b_, c_)
- #define ANKI_STATE_CMD_4(type_, glfunc_, a_, b_, c_, d_) \
- class Command: public GlCommand \
- { \
- public: \
- Array<type_, 4> m_value; \
- Command(type_ a, type_ b, type_ c, type_ d) \
- { \
- m_value = {{a, b, c, d}}; \
- } \
- Error operator()(CommandBufferImpl*) \
- { \
- glfunc_(m_value[0], m_value[1], m_value[2], m_value[3]); \
- return ErrorCode::NONE; \
- } \
- }; \
- _pushBackNewCommand<Command>(a_, b_, c_, d_)
- #define ANKI_STATE_CMD_ENABLE(enum_, enable_) \
- class Command: public GlCommand \
- { \
- public: \
- Bool8 m_enable; \
- Command(Bool enable) \
- : m_enable(enable) \
- {} \
- Error operator()(CommandBufferImpl*) \
- { \
- if(m_enable) \
- { \
- glEnable(enum_); \
- } \
- else \
- { \
- glDisable(enum_); \
- } \
- return ErrorCode::NONE; \
- } \
- }; \
- _pushBackNewCommand<Command>(enable_)
- //==============================================================================
- CommandBufferHandle::CommandBufferHandle()
- {}
- //==============================================================================
- CommandBufferHandle::~CommandBufferHandle()
- {}
- //==============================================================================
- Error CommandBufferHandle::create(GlDevice* gl,
- CommandBufferImplInitHints hints)
- {
- ANKI_ASSERT(!isCreated());
- ANKI_ASSERT(gl);
- using Alloc = GlAllocator<CommandBufferImpl>;
- Alloc alloc = gl->_getAllocator();
- Error err = _createAdvanced(
- gl,
- alloc,
- GlHandleDefaultDeleter<CommandBufferImpl, Alloc>());
- if(!err)
- {
- err = _get().create(&gl->_getRenderingThread(), hints);
- }
- return err;
- }
- //==============================================================================
- void CommandBufferHandle::pushBackUserCommand(
- UserCallback callback, void* data)
- {
- class Command: public GlCommand
- {
- public:
- UserCallback m_callback;
- void* m_userData;
- Command(UserCallback callback, void* userData)
- : m_callback(callback),
- m_userData(userData)
- {
- ANKI_ASSERT(m_callback);
- }
- Error operator()(CommandBufferImpl* commands)
- {
- return (*m_callback)(m_userData);
- }
- };
- _pushBackNewCommand<Command>(callback, data);
- }
- //==============================================================================
- void CommandBufferHandle::pushBackOtherCommandBuffer(
- CommandBufferHandle& commands)
- {
- class Command: public GlCommand
- {
- public:
- CommandBufferHandle m_commands;
- Command(CommandBufferHandle& commands)
- : m_commands(commands)
- {}
- Error operator()(CommandBufferImpl*)
- {
- return m_commands._executeAllCommands();
- }
- };
- commands._get().makeImmutable();
- _pushBackNewCommand<Command>(commands);
- }
- //==============================================================================
- void CommandBufferHandle::flush()
- {
- _get().getRenderingThread().flushCommandBuffer(*this);
- }
- //==============================================================================
- void CommandBufferHandle::finish()
- {
- _get().getRenderingThread().finishCommandBuffer(*this);
- }
- //==============================================================================
- void CommandBufferHandle::setClearColor(F32 r, F32 g, F32 b, F32 a)
- {
- ANKI_STATE_CMD_4(F32, glClearColor, r, g, b, a);
- }
- //==============================================================================
- void CommandBufferHandle::setClearDepth(F32 value)
- {
- ANKI_STATE_CMD_1(F32, glClearDepth, value);
- }
- //==============================================================================
- void CommandBufferHandle::setClearStencil(U32 value)
- {
- ANKI_STATE_CMD_1(U32, glClearStencil, value);
- }
- //==============================================================================
- void CommandBufferHandle::clearBuffers(U32 mask)
- {
- ANKI_STATE_CMD_1(U32, glClear, mask);
- }
- //==============================================================================
- void CommandBufferHandle::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
- {
- class Command: public GlCommand
- {
- public:
- Array<U16, 4> m_value;
-
- Command(U16 a, U16 b, U16 c, U16 d)
- {
- m_value = {{a, b, c, d}};
- }
- Error operator()(CommandBufferImpl* commands)
- {
- State& state = commands->getRenderingThread().getState();
- if(state.m_viewport[0] != m_value[0]
- || state.m_viewport[1] != m_value[1]
- || state.m_viewport[2] != m_value[2]
- || state.m_viewport[3] != m_value[3])
- {
- glViewport(m_value[0], m_value[1], m_value[2], m_value[3]);
- state.m_viewport = m_value;
- }
- return ErrorCode::NONE;
- }
- };
- _pushBackNewCommand<Command>(minx, miny, maxx, maxy);
- }
- //==============================================================================
- void CommandBufferHandle::setColorWriteMask(
- Bool red, Bool green, Bool blue, Bool alpha)
- {
- ANKI_STATE_CMD_4(Bool8, glColorMask, red, green, blue, alpha);
- }
- //==============================================================================
- void CommandBufferHandle::enableDepthTest(Bool enable)
- {
- ANKI_STATE_CMD_ENABLE(GL_DEPTH_TEST, enable);
- }
- //==============================================================================
- void CommandBufferHandle::setDepthFunction(GLenum func)
- {
- ANKI_STATE_CMD_1(GLenum, glDepthFunc, func);
- }
- //==============================================================================
- void CommandBufferHandle::setDepthWriteMask(Bool write)
- {
- ANKI_STATE_CMD_1(Bool8, glDepthMask, write);
- }
- //==============================================================================
- void CommandBufferHandle::enableStencilTest(Bool enable)
- {
- ANKI_STATE_CMD_ENABLE(GL_STENCIL_TEST, enable);
- }
- //==============================================================================
- void CommandBufferHandle::setStencilFunction(
- GLenum function, U32 reference, U32 mask)
- {
- ANKI_STATE_CMD_3(U32, glStencilFunc, function, reference, mask);
- }
- //==============================================================================
- void CommandBufferHandle::setStencilPlaneMask(U32 mask)
- {
- ANKI_STATE_CMD_1(U32, glStencilMask, mask);
- }
- //==============================================================================
- void CommandBufferHandle::setStencilOperations(GLenum stencFail, GLenum depthFail,
- GLenum depthPass)
- {
- ANKI_STATE_CMD_3(GLenum, glStencilOp, stencFail, depthFail, depthPass);
- }
- //==============================================================================
- void CommandBufferHandle::enableBlend(Bool enable)
- {
- ANKI_STATE_CMD_ENABLE(GL_BLEND, enable);
- }
- //==============================================================================
- void CommandBufferHandle::setBlendEquation(GLenum equation)
- {
- ANKI_STATE_CMD_1(GLenum, glBlendEquation, equation);
- }
- //==============================================================================
- void CommandBufferHandle::setBlendFunctions(GLenum sfactor, GLenum dfactor)
- {
- class Command: public GlCommand
- {
- public:
- GLenum m_sfactor;
- GLenum m_dfactor;
- Command(GLenum sfactor, GLenum dfactor)
- : m_sfactor(sfactor), m_dfactor(dfactor)
- {}
- Error operator()(CommandBufferImpl* commands)
- {
- State& state = commands->getRenderingThread().getState();
- if(state.m_blendSfunc != m_sfactor
- || state.m_blendDfunc != m_dfactor)
- {
- glBlendFunc(m_sfactor, m_dfactor);
- state.m_blendSfunc = m_sfactor;
- state.m_blendDfunc = m_dfactor;
- }
- return ErrorCode::NONE;
- }
- };
- _pushBackNewCommand<Command>(sfactor, dfactor);
- }
- //==============================================================================
- void CommandBufferHandle::setBlendColor(F32 r, F32 g, F32 b, F32 a)
- {
- ANKI_STATE_CMD_4(F32, glBlendColor, r, g, b, a);
- }
- //==============================================================================
- void CommandBufferHandle::enablePrimitiveRestart(Bool enable)
- {
- ANKI_STATE_CMD_ENABLE(GL_PRIMITIVE_RESTART, enable);
- }
- //==============================================================================
- void CommandBufferHandle::setPatchVertexCount(U32 count)
- {
- ANKI_STATE_CMD_2(GLint, glPatchParameteri, GL_PATCH_VERTICES, count);
- }
- //==============================================================================
- void CommandBufferHandle::enableCulling(Bool enable)
- {
- ANKI_STATE_CMD_ENABLE(GL_CULL_FACE, enable);
- }
- //==============================================================================
- void CommandBufferHandle::setCullFace(GLenum mode)
- {
- ANKI_STATE_CMD_1(GLenum, glCullFace, mode);
- }
- //==============================================================================
- void CommandBufferHandle::setPolygonOffset(F32 factor, F32 units)
- {
- ANKI_STATE_CMD_2(F32, glPolygonOffset, factor, units);
- }
- //==============================================================================
- void CommandBufferHandle::enablePolygonOffset(Bool enable)
- {
- ANKI_STATE_CMD_ENABLE(GL_POLYGON_OFFSET_FILL, enable);
- }
- //==============================================================================
- void CommandBufferHandle::setPolygonMode(GLenum face, GLenum mode)
- {
- ANKI_STATE_CMD_2(GLenum, glPolygonMode, face, mode);
- }
- //==============================================================================
- void CommandBufferHandle::enablePointSize(Bool enable)
- {
- ANKI_STATE_CMD_ENABLE(GL_PROGRAM_POINT_SIZE, enable);
- }
- //==============================================================================
- class BindTexturesCommand: public GlCommand
- {
- public:
- static const U MAX_BIND_TEXTURES = 8;
- Array<TextureHandle, MAX_BIND_TEXTURES> m_texes;
- U32 m_texCount;
- U32 m_first;
- BindTexturesCommand(
- TextureHandle textures[], U count, U32 first)
- : m_first(first)
- {
- m_texCount = count;
- TextureHandle* t = textures;
- while(count-- != 0)
- {
- m_texes[count] = *t;
- ++t;
- }
- }
- Error operator()(CommandBufferImpl* commands)
- {
- Array<GLuint, MAX_BIND_TEXTURES> names;
- U count = m_texCount;
- U i = 0;
- while(count-- != 0)
- {
- names[i++] = m_texes[count]._get().getGlName();
- }
- glBindTextures(m_first, m_texCount, &names[0]);
- return ErrorCode::NONE;
- }
- };
- void CommandBufferHandle::bindTextures(U32 first,
- TextureHandle textures[], U32 count)
- {
- ANKI_ASSERT(count > 0);
- _pushBackNewCommand<BindTexturesCommand>(&textures[0], count, first);
- }
- //==============================================================================
- class DrawElementsCondCommand: public GlCommand
- {
- public:
- GLenum m_mode;
- U8 m_indexSize;
- GlDrawElementsIndirectInfo m_info;
- OcclusionQueryHandle m_query;
- DrawElementsCondCommand(
- GLenum mode,
- U8 indexSize,
- GlDrawElementsIndirectInfo& info,
- OcclusionQueryHandle query = OcclusionQueryHandle())
- : m_mode(mode),
- m_indexSize(indexSize),
- m_info(info),
- m_query(query)
- {}
- Error operator()(CommandBufferImpl*)
- {
- ANKI_ASSERT(m_indexSize != 0);
- GLenum indicesType = 0;
- switch(m_indexSize)
- {
- case 1:
- indicesType = GL_UNSIGNED_BYTE;
- break;
- case 2:
- indicesType = GL_UNSIGNED_SHORT;
- break;
- case 4:
- indicesType = GL_UNSIGNED_INT;
- break;
- default:
- ANKI_ASSERT(0);
- break;
- };
- if(!m_query.isCreated() || !m_query._get().skipDrawcall())
- {
- glDrawElementsInstancedBaseVertexBaseInstance(
- m_mode,
- m_info.m_count,
- indicesType,
- (const void*)(PtrSize)(m_info.m_firstIndex * m_indexSize),
- m_info.m_instanceCount,
- m_info.m_baseVertex,
- m_info.m_baseInstance);
- ANKI_COUNTER_INC(GL_DRAWCALLS_COUNT, (U64)1);
- }
- return ErrorCode::NONE;
- }
- };
- void CommandBufferHandle::drawElements(
- GLenum mode, U8 indexSize, U32 count, U32 instanceCount, U32 firstIndex,
- U32 baseVertex, U32 baseInstance)
- {
- GlDrawElementsIndirectInfo info(count, instanceCount, firstIndex,
- baseVertex, baseInstance);
- _pushBackNewCommand<DrawElementsCondCommand>(mode, indexSize, info);
- }
- //==============================================================================
- class DrawArraysCondCommand: public GlCommand
- {
- public:
- GLenum m_mode;
- GlDrawArraysIndirectInfo m_info;
- OcclusionQueryHandle m_query;
- DrawArraysCondCommand(
- GLenum mode,
- GlDrawArraysIndirectInfo& info,
- OcclusionQueryHandle query = OcclusionQueryHandle())
- : m_mode(mode),
- m_info(info),
- m_query(query)
- {}
- Error operator()(CommandBufferImpl*)
- {
- if(!m_query.isCreated() || !m_query._get().skipDrawcall())
- {
- glDrawArraysInstancedBaseInstance(
- m_mode,
- m_info.m_first,
- m_info.m_count,
- m_info.m_instanceCount,
- m_info.m_baseInstance);
- ANKI_COUNTER_INC(GL_DRAWCALLS_COUNT, (U64)1);
- }
- return ErrorCode::NONE;
- }
- };
- void CommandBufferHandle::drawArrays(
- GLenum mode, U32 count, U32 instanceCount, U32 first, U32 baseInstance)
- {
- GlDrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
- _pushBackNewCommand<DrawArraysCondCommand>(mode, info);
- }
- //==============================================================================
- void CommandBufferHandle::drawElementsConditional(
- OcclusionQueryHandle& query,
- GLenum mode, U8 indexSize, U32 count, U32 instanceCount, U32 firstIndex,
- U32 baseVertex, U32 baseInstance)
- {
- GlDrawElementsIndirectInfo info(count, instanceCount, firstIndex,
- baseVertex, baseInstance);
- _pushBackNewCommand<DrawElementsCondCommand>(mode, indexSize, info, query);
- }
- //==============================================================================
- void CommandBufferHandle::drawArraysConditional(
- OcclusionQueryHandle& query,
- GLenum mode, U32 count, U32 instanceCount, U32 first, U32 baseInstance)
- {
- GlDrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
- _pushBackNewCommand<DrawArraysCondCommand>(mode, info, query);
- }
- //==============================================================================
- class CopyBuffTex: public GlCommand
- {
- public:
- TextureHandle m_tex;
- BufferHandle m_buff;
- CopyBuffTex(TextureHandle& from, BufferHandle& to)
- : m_tex(from),
- m_buff(to)
- {}
- Error operator()(CommandBufferImpl* cmd)
- {
- TextureImpl& tex = m_tex._get();
- BufferImpl& buff = m_buff._get();
- // Bind
- GLuint copyFbo = cmd->getRenderingThread().getCopyFbo();
- glBindFramebuffer(GL_FRAMEBUFFER, copyFbo);
- // Attach texture
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- tex.getTarget(), tex.getGlName(), 0);
- // Set draw buffers
- GLuint drawBuff = GL_COLOR_ATTACHMENT0;
- glDrawBuffers(1, &drawBuff);
- // Bind buffer
- ANKI_ASSERT(m_buff.getTarget() == GL_PIXEL_PACK_BUFFER);
- buff.bind();
- // Read pixels
- GLuint format, type;
- if(tex.getInternalFormat() == GL_RG32UI)
- {
- format = GL_RG_INTEGER;
- type = GL_UNSIGNED_INT;
- }
- else if(tex.getInternalFormat() == GL_RG32F)
- {
- format = GL_RG;
- type = GL_FLOAT;
- }
- else
- {
- ANKI_ASSERT(0 && "Not implemented");
- }
- glReadPixels(0, 0, tex.getWidth(), tex.getHeight(),
- format, type, nullptr);
- // End
- buff.unbind();
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- return ErrorCode::NONE;
- }
- };
- void CommandBufferHandle::copyTextureToBuffer(
- TextureHandle& from, BufferHandle& to)
- {
- _pushBackNewCommand<CopyBuffTex>(from, to);
- }
- } // end namespace anki
|