/**************************************************************************** * Copyright (C) 2015 Dimok * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . ****************************************************************************/ #include #include #include "CVideo.h" #include "system/memory.h" #include "shaders/Texture2DShader.h" #include "shaders/ColorShader.h" #include "shaders/Shader3D.h" #include "shaders/ShaderFractalColor.h" #include "shaders/FXAAShader.h" CVideo::CVideo(s32 forceTvScanMode, s32 forceDrcScanMode) { tvEnabled = false; drcEnabled = false; //! allocate MEM2 command buffer memory gx2CommandBuffer = MEM2_alloc(GX2_COMMAND_BUFFER_SIZE, 0x40); //! initialize GX2 command buffer u32 gx2_init_attributes[9]; gx2_init_attributes[0] = GX2_INIT_CMD_BUF_BASE; gx2_init_attributes[1] = (u32)gx2CommandBuffer; gx2_init_attributes[2] = GX2_INIT_CMD_BUF_POOL_SIZE; gx2_init_attributes[3] = GX2_COMMAND_BUFFER_SIZE; gx2_init_attributes[4] = GX2_INIT_ARGC; gx2_init_attributes[5] = 0; gx2_init_attributes[6] = GX2_INIT_ARGV; gx2_init_attributes[7] = 0; gx2_init_attributes[8] = GX2_INIT_END; GX2Init(gx2_init_attributes); u32 scanBufferSize = 0; u32 scaleNeeded = 0; s32 tvScanMode = ((forceTvScanMode >= 0) ? forceTvScanMode : (s32)GX2GetSystemTVScanMode()); s32 drcScanMode = ((forceDrcScanMode >= 0) ? forceDrcScanMode : (s32)GX2GetSystemDRCScanMode()); s32 tvRenderMode; u32 tvWidth = 0; u32 tvHeight = 0; switch(tvScanMode) { case GX2_TV_SCAN_MODE_480I: case GX2_TV_SCAN_MODE_480P: tvWidth = 854; tvHeight = 480; tvRenderMode = GX2_TV_RENDER_MODE_WIDE_480P; break; case GX2_TV_SCAN_MODE_1080I: case GX2_TV_SCAN_MODE_1080P: tvWidth = 1920; tvHeight = 1080; tvRenderMode = GX2_TV_RENDER_MODE_WIDE_1080P; break; case GX2_TV_SCAN_MODE_720P: default: tvWidth = 1280; tvHeight = 720; tvRenderMode = GX2_TV_RENDER_MODE_WIDE_720P; break; } s32 tvAAMode = GX2_AA_MODE1X; s32 drcAAMode = GX2_AA_MODE4X; //! calculate the scale factor for later texture resize widthScaleFactor = 1.0f / (f32)tvWidth; heightScaleFactor = 1.0f / (f32)tvHeight; depthScaleFactor = widthScaleFactor; //! calculate the size needed for the TV scan buffer and allocate the buffer from bucket memory GX2CalcTVSize((GX2TVRenderMode)tvRenderMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE, &scanBufferSize, &scaleNeeded); tvScanBuffer = MEMBucket_alloc(scanBufferSize, GX2_SCAN_BUFFER_ALIGNMENT); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, tvScanBuffer, scanBufferSize); GX2SetTVBuffer(tvScanBuffer, scanBufferSize, (GX2TVRenderMode)tvRenderMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE); //! calculate the size needed for the DRC scan buffer and allocate the buffer from bucket memory GX2CalcDRCSize((GX2DrcRenderMode)drcScanMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE, &scanBufferSize, &scaleNeeded); drcScanBuffer = MEMBucket_alloc(scanBufferSize, GX2_SCAN_BUFFER_ALIGNMENT); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, drcScanBuffer, scanBufferSize); GX2SetDRCBuffer(drcScanBuffer, scanBufferSize, (GX2DrcRenderMode)drcScanMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE); //! Setup color buffer for TV rendering GX2InitColorBuffer(&tvColorBuffer, GX2_SURFACE_DIM_TEXTURE_2D, tvWidth, tvHeight, 1, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, (GX2AAMode)tvAAMode); tvColorBuffer.surface.image = MEM1_alloc(tvColorBuffer.surface.imageSize, tvColorBuffer.surface.alignment); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, tvColorBuffer.surface.image, tvColorBuffer.surface.imageSize); //! due to AA we can only use 16 bit depth buffer in MEM1 otherwise we would have to switch to mem2 for depth buffer //! this should be ok for our purpose i guess //! Setup TV depth buffer (can be the same for both if rendered one after another) u32 size, align; GX2InitDepthBuffer(&tvDepthBuffer, GX2_SURFACE_DIM_TEXTURE_2D, tvColorBuffer.surface.width, tvColorBuffer.surface.height, 1, GX2_SURFACE_FORMAT_FLOAT_R32, (GX2AAMode)tvAAMode); tvDepthBuffer.surface.image = MEM1_alloc(tvDepthBuffer.surface.imageSize, tvDepthBuffer.surface.alignment); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, tvDepthBuffer.surface.image, tvDepthBuffer.surface.imageSize); //! Setup TV HiZ buffer GX2CalcDepthBufferHiZInfo(&tvDepthBuffer, &size, &align); tvDepthBuffer.hiZPtr = MEM1_alloc(size, align); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, tvDepthBuffer.hiZPtr, size); GX2InitDepthBufferHiZEnable(&tvDepthBuffer, GX2_ENABLE); //! Setup color buffer for DRC rendering GX2InitColorBuffer(&drcColorBuffer, GX2_SURFACE_DIM_TEXTURE_2D, 854, 480, 1, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, (GX2AAMode)drcAAMode); drcColorBuffer.surface.image = MEM1_alloc(drcColorBuffer.surface.imageSize, drcColorBuffer.surface.alignment); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, drcColorBuffer.surface.image, drcColorBuffer.surface.imageSize); //! Setup DRC depth buffer (can be the same for both if rendered one after another) GX2InitDepthBuffer(&drcDepthBuffer, GX2_SURFACE_DIM_TEXTURE_2D, drcColorBuffer.surface.width, drcColorBuffer.surface.height, 1, GX2_SURFACE_FORMAT_FLOAT_R32, (GX2AAMode)drcAAMode); drcDepthBuffer.surface.image = MEM1_alloc(drcDepthBuffer.surface.imageSize, drcDepthBuffer.surface.alignment); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, drcDepthBuffer.surface.image, drcDepthBuffer.surface.imageSize); //! Setup DRC HiZ buffer GX2CalcDepthBufferHiZInfo(&drcDepthBuffer, &size, &align); drcDepthBuffer.hiZPtr = MEM1_alloc(size, align); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, drcDepthBuffer.hiZPtr, size); GX2InitDepthBufferHiZEnable(&drcDepthBuffer, GX2_ENABLE); //! allocate auxilary buffer last as there might not be enough MEM1 left for other stuff after that if (tvColorBuffer.surface.aa) { u32 auxSize, auxAlign; GX2CalcColorBufferAuxInfo(&tvColorBuffer, &auxSize, &auxAlign); tvColorBuffer.aaBuffer = MEM1_alloc(auxSize, auxAlign); if(!tvColorBuffer.aaBuffer) tvColorBuffer.aaBuffer = MEM2_alloc(auxSize, auxAlign); tvColorBuffer.aaSize = auxSize; memset(tvColorBuffer.aaBuffer, GX2_AA_BUFFER_CLEAR_VALUE, auxSize); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, tvColorBuffer.aaBuffer, auxSize); } if (drcColorBuffer.surface.aa) { u32 auxSize, auxAlign; GX2CalcColorBufferAuxInfo(&drcColorBuffer, &auxSize, &auxAlign); drcColorBuffer.aaBuffer = MEM1_alloc(auxSize, auxAlign); if(!drcColorBuffer.aaBuffer) drcColorBuffer.aaBuffer = MEM2_alloc(auxSize, auxAlign); drcColorBuffer.aaSize = auxSize; memset(drcColorBuffer.aaBuffer, GX2_AA_BUFFER_CLEAR_VALUE, auxSize); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, drcColorBuffer.aaBuffer, auxSize); } //! allocate memory and setup context state TV tvContextState = (GX2ContextState*)MEM2_alloc(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT); GX2SetupContextStateEx(tvContextState, GX2_TRUE); //! allocate memory and setup context state DRC drcContextState = (GX2ContextState*)MEM2_alloc(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT); GX2SetupContextStateEx(drcContextState, GX2_TRUE); //! set initial context state and render buffers GX2SetContextState(tvContextState); GX2SetColorBuffer(&tvColorBuffer, GX2_RENDER_TARGET_0); GX2SetDepthBuffer(&tvDepthBuffer); GX2SetContextState(drcContextState); GX2SetColorBuffer(&drcColorBuffer, GX2_RENDER_TARGET_0); GX2SetDepthBuffer(&drcDepthBuffer); //! set initial viewport GX2SetViewport(0.0f, 0.0f, tvColorBuffer.surface.width, tvColorBuffer.surface.height, 0.0f, 1.0f); GX2SetScissor(0, 0, tvColorBuffer.surface.width, tvColorBuffer.surface.height); //! this is not necessary but can be used for swap counting and vsyncs GX2SetSwapInterval(1); //GX2SetTVGamma(0.8f); //GX2SetDRCGamma(0.8f); //! initialize perspective matrix const float cam_X_rot = 25.0f; projectionMtx = glm::perspective(45.0f, 1.0f, 0.1f, 100.0f); viewMtx = glm::mat4(1.0f); viewMtx = glm::translate(viewMtx, glm::vec3(0.0f, 0.0f, -2.5f)); viewMtx = glm::rotate(viewMtx, DegToRad(cam_X_rot), glm::vec3(1.0f, 0.0f, 0.0f)); GX2InitSampler(&aaSampler, GX2_TEX_CLAMP_MODE_CLAMP, GX2_TEX_XY_FILTER_MODE_LINEAR); GX2InitTexture(&tvAaTexture, tvColorBuffer.surface.width, tvColorBuffer.surface.height, 1, 0, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_SURFACE_DIM_TEXTURE_2D, GX2_TILE_MODE_DEFAULT); tvAaTexture.surface.image = tvColorBuffer.surface.image; tvAaTexture.surface.imageSize = tvColorBuffer.surface.imageSize; tvAaTexture.surface.mipmaps = tvColorBuffer.surface.mipmaps; } CVideo::~CVideo() { //! flush buffers GX2Flush(); GX2DrawDone(); //! shutdown GX2Shutdown(); //! free command buffer memory MEM2_free(gx2CommandBuffer); //! free scan buffers MEMBucket_free(tvScanBuffer); MEMBucket_free(drcScanBuffer); //! free color buffers MEM1_free(tvColorBuffer.surface.image); MEM1_free(drcColorBuffer.surface.image); //! free depth buffers MEM1_free(tvDepthBuffer.surface.image); MEM1_free(tvDepthBuffer.hiZPtr); MEM1_free(drcDepthBuffer.surface.image); MEM1_free(drcDepthBuffer.hiZPtr); //! free context buffers MEM2_free(tvContextState); MEM2_free(drcContextState); //! free aux buffer if(tvColorBuffer.aaBuffer) { if(((u32)tvColorBuffer.aaBuffer & 0xF0000000) == 0xF0000000) MEM1_free(tvColorBuffer.aaBuffer); else MEM2_free(tvColorBuffer.aaBuffer); } if(drcColorBuffer.aaBuffer) { if(((u32)drcColorBuffer.aaBuffer & 0xF0000000) == 0xF0000000) MEM1_free(drcColorBuffer.aaBuffer); else MEM2_free(drcColorBuffer.aaBuffer); } //! destroy shaders ColorShader::destroyInstance(); FXAAShader::destroyInstance(); Shader3D::destroyInstance(); ShaderFractalColor::destroyInstance(); Texture2DShader::destroyInstance(); } void CVideo::renderFXAA(const GX2Texture * texture, const GX2Sampler *sampler) { resolution[0] = texture->surface.width; resolution[1] = texture->surface.height; GX2Invalidate((GX2InvalidateMode)(GX2_INVALIDATE_MODE_COLOR_BUFFER | GX2_INVALIDATE_MODE_TEXTURE), texture->surface.image, texture->surface.imageSize); GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_FUNC_ALWAYS); FXAAShader::instance()->setShaders(); FXAAShader::instance()->setAttributeBuffer(); FXAAShader::instance()->setResolution(resolution); FXAAShader::instance()->setTextureAndSampler(texture, sampler); FXAAShader::instance()->draw(); GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_FUNC_LEQUAL); } void* CVideo::GX2RAlloc(u32 flags, u32 size, u32 align) { //! min. alignment if (align < 4) align = 4; if ((flags & 0x2040E) && !(flags & 0x40000)) return MEM1_alloc(size, align); else return MEM2_alloc(size, align); } void CVideo::GX2RFree(u32 flags, void* p) { if ((flags & 0x2040E) && !(flags & 0x40000)) MEM1_free(p); else MEM2_free(p); }