//============================================================================== Error GlPipelineHandle::commonConstructor( GlCommandBufferHandle& commands, const GlShaderHandle* progsBegin, const GlShaderHandle* progsEnd) { class Command: public GlCommand { public: GlPipelineHandle m_ppline; Array<GlShaderHandle, 6> m_progs; U8 m_progsCount; Command(GlPipelineHandle& ppline, const GlShaderHandle* progsBegin, const GlShaderHandle* progsEnd) : m_ppline(ppline) { m_progsCount = 0; const GlShaderHandle* prog = progsBegin; do { m_progs[m_progsCount++] = *prog; } while(++prog != progsEnd); } Error operator()(GlCommandBuffer* cmdb) { Error err = m_ppline._get().create( &m_progs[0], &m_progs[0] + m_progsCount, cmdb->getGlobalAllocator()); GlHandleState oldState = m_ppline._setState( err ? GlHandleState::ERROR : GlHandleState::CREATED); ANKI_ASSERT(oldState == GlHandleState::TO_BE_CREATED); (void)oldState; return err; } }; using Alloc = GlAllocator<GlPipeline>; using DeleteCommand = GlDeleteObjectCommand<GlPipeline, Alloc>; using Deleter = GlHandleDeferredDeleter<GlPipeline, Alloc, DeleteCommand>; Error err = _createAdvanced( &commands._get().getQueue().getDevice(), commands._get().getGlobalAllocator(), Deleter()); if(!err) { _setState(GlHandleState::TO_BE_CREATED); commands._pushBackNewCommand<Command>(*this, progsBegin, progsEnd); } return err; }
//============================================================================== Error Material::getProgramPipeline( const RenderingKey& key, GlPipelineHandle& out) { ANKI_ASSERT(enumToType(key.m_pass) < m_passesCount); ANKI_ASSERT(key.m_lod < m_lodsCount); Error err = ErrorCode::NONE; U tessCount = 1; if(m_tessellation) { tessCount = 2; } else { ANKI_ASSERT(!key.m_tessellation); } U idx = enumToType(key.m_pass) * m_lodsCount * tessCount + key.m_lod * tessCount + key.m_tessellation; GlPipelineHandle& ppline = m_pplines[idx]; // Lazily create it if(ANKI_UNLIKELY(!ppline.isCreated())) { Array<GlShaderHandle, 5> progs; U progCount = 0; progs[progCount++] = getProgram(key, ShaderType::VERTEX)->getGlProgram(); if(key.m_tessellation) { progs[progCount++] = getProgram( key, ShaderType::TESSELLATION_CONTROL)->getGlProgram(); progs[progCount++] = getProgram( key, ShaderType::TESSELLATION_EVALUATION)->getGlProgram(); } progs[progCount++] = getProgram(key, ShaderType::FRAGMENT)->getGlProgram(); GlDevice& gl = m_resources->_getGlDevice(); GlCommandBufferHandle cmdBuff; ANKI_CHECK(cmdBuff.create(&gl)); ANKI_CHECK(ppline.create(cmdBuff, &progs[0], &progs[0] + progCount)); cmdBuff.flush(); } out = ppline; return err; }
//============================================================================== void Pps::initInternal(const ConfigSet& config) { m_enabled = config.get("pps.enabled"); if(!m_enabled) { return; } ANKI_ASSERT("Initializing PPS"); m_ssao.init(config); m_hdr.init(config); m_lf.init(config); m_sslr.init(config); // FBO GlCommandBufferHandle cmdBuff; cmdBuff.create(&getGlDevice()); m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(), GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, 1, m_rt); m_fb.create(cmdBuff, {{m_rt, GL_COLOR_ATTACHMENT0}}); // SProg String pps(getAllocator()); pps.sprintf( "#define SSAO_ENABLED %u\n" "#define HDR_ENABLED %u\n" "#define SHARPEN_ENABLED %u\n" "#define GAMMA_CORRECTION_ENABLED %u\n" "#define FBO_WIDTH %u\n" "#define FBO_HEIGHT %u\n", m_ssao.getEnabled(), m_hdr.getEnabled(), static_cast<U>(config.get("pps.sharpen")), static_cast<U>(config.get("pps.gammaCorrection")), m_r->getWidth(), m_r->getHeight()); m_frag.loadToCache(&getResourceManager(), "shaders/Pps.frag.glsl", pps.toCString(), "r_"); m_ppline = m_r->createDrawQuadProgramPipeline(m_frag->getGlProgram()); cmdBuff.finish(); }
//============================================================================== void Hdr::run(GlCommandBufferHandle& jobs) { ANKI_ASSERT(m_enabled); // For the passes it should be NEAREST //vblurFai.setFiltering(Texture::TFrustumType::NEAREST); // pass 0 m_vblurFb.bind(jobs, true); jobs.setViewport(0, 0, m_width, m_height); m_tonePpline.bind(jobs); if(m_parameterUpdateTimestamp > m_commonUboUpdateTimestamp) { updateDefaultBlock(jobs); m_commonUboUpdateTimestamp = getGlobTimestamp(); } m_r->getIs()._getRt().bind(jobs, 0); m_commonBuff.bindShaderBuffer(jobs, 0); m_r->drawQuad(jobs); // Blurring passes for(U32 i = 0; i < m_blurringIterationsCount; i++) { if(i == 0) { jobs.bindTextures(0, {m_hblurRt, m_vblurRt}); } // hpass m_hblurFb.bind(jobs, true); m_hblurPpline.bind(jobs); m_r->drawQuad(jobs); // vpass m_vblurFb.bind(jobs, true); m_vblurPpline.bind(jobs); m_r->drawQuad(jobs); } // For the next stage it should be LINEAR though //vblurFai.setFiltering(Texture::TFrustumType::LINEAR); }
Error operator()(GlCommandBuffer* commands) { GlState& state = commands->getQueue().getState(); if(state.m_crntPpline != m_ppline._get().getGlName()) { m_ppline._get().bind(); state.m_crntPpline = m_ppline._get().getGlName(); } return ErrorCode::NONE; }
//============================================================================== GlBufferHandle::GlBufferHandle(GlCommandBufferHandle& commands, GLenum target, PtrSize size, GLenum flags) { ANKI_ASSERT(!isCreated()); using Alloc = GlGlobalHeapAllocator<GlBuffer>; using DeleteCommand = GlDeleteObjectCommand<GlBuffer, GlGlobalHeapAllocator<U8>>; using Deleter = GlHandleDeferredDeleter<GlBuffer, Alloc, DeleteCommand>; *static_cast<Base::Base*>(this) = Base::Base( &commands._getQueue().getDevice(), commands._getQueue().getDevice()._getAllocator(), Deleter()); _setState(GlHandleState::TO_BE_CREATED); // Fire the command commands._pushBackNewCommand<GlBufferCreateCommand>( *this, target, size, flags); }
Error operator()(GlCommandBuffer* commands) { GlState& state = commands->getQueue().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; }
Error operator()(GlCommandBuffer* commands) { GlState& state = commands->getQueue().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; }
//============================================================================== void GlCommandBufferHandle::pushBackOtherCommandBuffer( GlCommandBufferHandle& commands) { class Command: public GlCommand { public: GlCommandBufferHandle m_commands; Command(GlCommandBufferHandle& commands) : m_commands(commands) {} Error operator()(GlCommandBuffer*) { return m_commands._executeAllCommands(); } }; commands._get().makeImmutable(); _pushBackNewCommand<Command>(commands); }
//============================================================================== void Bs::run(GlCommandBufferHandle& jobs) { jobs.enableDepthTest(true); jobs.setDepthWriteMask(false); jobs.enableBlend(true); RenderableDrawer& drawer = m_r->getSceneDrawer(); drawer.prepareDraw(RenderingStage::BLEND, Pass::COLOR, jobs); Camera& cam = m_r->getSceneGraph().getActiveCamera(); for(auto& it : cam.getVisibilityTestResults().m_renderables) { drawer.render(cam, it); } drawer.finishDraw(); jobs.enableDepthTest(false); jobs.setDepthWriteMask(true); jobs.enableBlend(false); }
Error operator()(GlCommandBuffer*) { return m_commands._executeAllCommands(); }
//============================================================================== void TextureResource::loadInternal(const CString& filename, ResourceInitializer& rinit) { GlDevice& gl = rinit.m_resources._getGlDevice(); GlCommandBufferHandle cmdb; cmdb.create(&gl); // Always first to avoid assertions ( // because of the check of the allocator) GlTextureHandle::Initializer init; U layers = 0; Bool driverShouldGenMipmaps = false; // Load image Image* imgPtr = rinit.m_alloc.newInstance<Image>(rinit.m_alloc); Image& img = *imgPtr; img.load(filename, rinit.m_resources.getMaxTextureSize()); // width + height init.m_width = img.getSurface(0, 0).m_width; init.m_height = img.getSurface(0, 0).m_height; // depth if(img.getTextureType() == Image::TextureType::_2D_ARRAY || img.getTextureType() == Image::TextureType::_3D) { init.m_depth = img.getDepth(); } else { init.m_depth = 0; } // target switch(img.getTextureType()) { case Image::TextureType::_2D: init.m_target = GL_TEXTURE_2D; layers = 1; break; case Image::TextureType::CUBE: init.m_target = GL_TEXTURE_CUBE_MAP; layers = 6; break; case Image::TextureType::_2D_ARRAY: init.m_target = GL_TEXTURE_2D_ARRAY; layers = init.m_depth; break; case Image::TextureType::_3D: init.m_target = GL_TEXTURE_3D; layers = init.m_depth; default: ANKI_ASSERT(0); } // Internal format if(img.getColorFormat() == Image::ColorFormat::RGB8) { switch(img.getCompression()) { case Image::DataCompression::RAW: #if DRIVER_CAN_COMPRESS init.m_internalFormat = GL_COMPRESSED_RGB; #else init.m_internalFormat = GL_RGB; #endif driverShouldGenMipmaps = true; break; #if ANKI_GL == ANKI_GL_DESKTOP case Image::DataCompression::S3TC: init.m_internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; #else case Image::DataCompression::ETC: init.m_internalFormat = GL_COMPRESSED_RGB8_ETC2; break; #endif default: ANKI_ASSERT(0); } } else if(img.getColorFormat() == Image::ColorFormat::RGBA8) { switch(img.getCompression()) { case Image::DataCompression::RAW: #if DRIVER_CAN_COMPRESS init.m_internalFormat = GL_COMPRESSED_RGBA; #else init.m_internalFormat = GL_RGBA; #endif driverShouldGenMipmaps = true; break; #if ANKI_GL == ANKI_GL_DESKTOP case Image::DataCompression::S3TC: init.m_internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; #else case Image::DataCompression::ETC: init.m_internalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; break; #endif default: ANKI_ASSERT(0); } } else { ANKI_ASSERT(0); } // format switch(img.getColorFormat()) { case Image::ColorFormat::RGB8: init.m_format = GL_RGB; break; case Image::ColorFormat::RGBA8: init.m_format = GL_RGBA; break; default: ANKI_ASSERT(0); } // type init.m_type = GL_UNSIGNED_BYTE; // mipmapsCount init.m_mipmapsCount = img.getMipLevelsCount(); // filteringType init.m_filterType = GlTextureHandle::Filter::TRILINEAR; // repeat init.m_repeat = true; // anisotropyLevel init.m_anisotropyLevel = rinit.m_resources.getTextureAnisotropy(); // genMipmaps if(init.m_mipmapsCount == 1 || driverShouldGenMipmaps) { init.m_genMipmaps = true; } else { init.m_genMipmaps = false; } // Now assign the data for(U layer = 0; layer < layers; layer++) { for(U level = 0; level < init.m_mipmapsCount; level++) { GlClientBufferHandle& buff = init.m_data[level][layer]; buff.create( cmdb, img.getSurface(level, layer).m_data.size(), (void*)&img.getSurface(level, layer).m_data[0]); } } // Add the GL job to create the texture m_tex.create(cmdb, init); // Add cleanup job cmdb.pushBackUserCommand(deleteImageCallback, imgPtr); // Finaly enque the GL job chain cmdb.flush(); m_size = UVec3(init.m_width, init.m_height, init.m_depth); }
//============================================================================== void Pps::run(GlCommandBufferHandle& cmdBuff) { ANKI_ASSERT(m_enabled); // First SSAO because it depends on MS where HDR depends on IS if(m_ssao.getEnabled()) { m_ssao.run(cmdBuff); } // Then SSLR because HDR depends on it if(m_sslr.getEnabled()) { m_sslr.run(cmdBuff); } if(m_hdr.getEnabled()) { m_hdr.run(cmdBuff); } if(m_lf.getEnabled()) { m_lf.run(cmdBuff); } Bool drawToDefaultFbo = !m_r->getDbg().getEnabled() && !m_r->getIsOffscreen() && m_r->getRenderingQuality() == 1.0; if(drawToDefaultFbo) { m_r->getDefaultFramebuffer().bind(cmdBuff, true); cmdBuff.setViewport(0, 0, m_r->getWindowWidth(), m_r->getWindowHeight()); } else { m_fb.bind(cmdBuff, true); cmdBuff.setViewport(0, 0, m_r->getWidth(), m_r->getHeight()); } m_ppline.bind(cmdBuff); m_r->getIs()._getRt().bind(cmdBuff, 0); if(m_ssao.getEnabled()) { m_ssao.getRt().bind(cmdBuff, 1); } if(m_lf.getEnabled()) { m_lf._getRt().bind(cmdBuff, 2); } else if(m_hdr.getEnabled()) { m_hdr._getRt().bind(cmdBuff, 2); } m_r->drawQuad(cmdBuff); }
//============================================================================== void Ssao::initInternal(const ConfigSet& config) { m_enabled = config.get("pps.ssao.enabled"); if(!m_enabled) { return; } m_blurringIterationsCount = config.get("pps.ssao.blurringIterationsCount"); // // Init the widths/heights // const F32 quality = config.get("pps.ssao.renderingQuality"); m_width = quality * (F32)m_r->getWidth(); alignRoundUp(16, m_width); m_height = quality * (F32)m_r->getHeight(); alignRoundUp(16, m_height); // // create FBOs // createFb(m_hblurFb, m_hblurRt); createFb(m_vblurFb, m_vblurRt); // // noise texture // GlCommandBufferHandle cmdb; cmdb.create(&getGlDevice()); GlClientBufferHandle noise; noise.create( cmdb, sizeof(Vec3) * NOISE_TEX_SIZE * NOISE_TEX_SIZE, nullptr); genNoise((Vec3*)noise.getBaseAddress(), (Vec3*)((U8*)noise.getBaseAddress() + noise.getSize())); GlTextureHandle::Initializer tinit; tinit.m_width = tinit.m_height = NOISE_TEX_SIZE; tinit.m_target = GL_TEXTURE_2D; tinit.m_internalFormat = GL_RGB32F; tinit.m_format = GL_RGB; tinit.m_type = GL_FLOAT; tinit.m_filterType = GlTextureHandle::Filter::NEAREST; tinit.m_repeat = true; tinit.m_mipmapsCount = 1; tinit.m_data[0][0] = noise; m_noiseTex.create(cmdb, tinit); // // Kernel // String kernelStr(getAllocator()); Array<Vec3, KERNEL_SIZE> kernel; genKernel(kernel.begin(), kernel.end()); kernelStr = "vec3[]("; for(U i = 0; i < kernel.size(); i++) { String tmp(getAllocator()); tmp.sprintf("vec3(%f, %f, %f) %s", kernel[i].x(), kernel[i].y(), kernel[i].z(), (i != kernel.size() - 1) ? ", " : ")"); kernelStr += tmp; } // // Shaders // m_uniformsBuff.create(cmdb, GL_SHADER_STORAGE_BUFFER, sizeof(ShaderCommonUniforms), GL_DYNAMIC_STORAGE_BIT); String pps(getAllocator()); // main pass prog pps.sprintf( "#define NOISE_MAP_SIZE %u\n" "#define WIDTH %u\n" "#define HEIGHT %u\n" "#define KERNEL_SIZE %u\n" "#define KERNEL_ARRAY %s\n", NOISE_TEX_SIZE, m_width, m_height, KERNEL_SIZE, &kernelStr[0]); m_ssaoFrag.loadToCache(&getResourceManager(), "shaders/PpsSsao.frag.glsl", pps.toCString(), "r_"); m_ssaoPpline = m_r->createDrawQuadProgramPipeline( m_ssaoFrag->getGlProgram()); // blurring progs const char* SHADER_FILENAME = "shaders/VariableSamplingBlurGeneric.frag.glsl"; pps.sprintf( "#define HPASS\n" "#define COL_R\n" "#define IMG_DIMENSION %u\n" "#define SAMPLES 7\n", m_height); m_hblurFrag.loadToCache(&getResourceManager(), SHADER_FILENAME, pps.toCString(), "r_"); m_hblurPpline = m_r->createDrawQuadProgramPipeline( m_hblurFrag->getGlProgram()); pps.sprintf( "#define VPASS\n" "#define COL_R\n" "#define IMG_DIMENSION %u\n" "#define SAMPLES 7\n", m_width); m_vblurFrag.loadToCache(&getResourceManager(), SHADER_FILENAME, pps.toCString(), "r_"); m_vblurPpline = m_r->createDrawQuadProgramPipeline( m_vblurFrag->getGlProgram()); cmdb.flush(); }
//============================================================================== void Ssao::run(GlCommandBufferHandle& cmdb) { ANKI_ASSERT(m_enabled); const Camera& cam = m_r->getSceneGraph().getActiveCamera(); cmdb.setViewport(0, 0, m_width, m_height); // 1st pass // m_vblurFb.bind(cmdb, true); m_ssaoPpline.bind(cmdb); m_uniformsBuff.bindShaderBuffer(cmdb, 0); Array<GlTextureHandle, 3> tarr = {{ m_r->getMs()._getSmallDepthRt(), m_r->getMs()._getRt1(), m_noiseTex}}; cmdb.bindTextures(0, tarr.begin(), tarr.getSize()); // Write common block if(m_commonUboUpdateTimestamp < m_r->getProjectionParametersUpdateTimestamp() || m_commonUboUpdateTimestamp < cam.FrustumComponent::getTimestamp() || m_commonUboUpdateTimestamp == 1) { GlClientBufferHandle tmpBuff; tmpBuff.create(cmdb, sizeof(ShaderCommonUniforms), nullptr); ShaderCommonUniforms& blk = *((ShaderCommonUniforms*)tmpBuff.getBaseAddress()); blk.m_projectionParams = m_r->getProjectionParameters(); blk.m_projectionMatrix = cam.getProjectionMatrix().getTransposed(); m_uniformsBuff.write(cmdb, tmpBuff, 0, 0, tmpBuff.getSize()); m_commonUboUpdateTimestamp = getGlobTimestamp(); } // Draw m_r->drawQuad(cmdb); // Blurring passes // for(U i = 0; i < m_blurringIterationsCount; i++) { if(i == 0) { Array<GlTextureHandle, 2> tarr = {{m_hblurRt, m_vblurRt}}; cmdb.bindTextures(0, tarr.begin(), tarr.getSize()); } // hpass m_hblurFb.bind(cmdb, true); m_hblurPpline.bind(cmdb); m_r->drawQuad(cmdb); // vpass m_vblurFb.bind(cmdb, true); m_vblurPpline.bind(cmdb); m_r->drawQuad(cmdb); } }