mirror of
https://github.com/wiiu-env/libgui.git
synced 2024-11-10 18:35:07 +01:00
264 lines
12 KiB
C++
264 lines
12 KiB
C++
/****************************************************************************
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
****************************************************************************/
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
#include <gui/video/CVideo.h>
|
|
#include <gui/memory.h>
|
|
#include <gui/video/shaders/Texture2DShader.h>
|
|
#include <gui/video/shaders/ColorShader.h>
|
|
#include <gui/video/shaders/Shader3D.h>
|
|
#include <gui/video/shaders/ShaderFractalColor.h>
|
|
#include <gui/video/shaders/FXAAShader.h>
|
|
#include "utils/utils.h"
|
|
|
|
CVideo::CVideo(int32_t forceTvScanMode, int32_t forceDrcScanMode) {
|
|
tvEnabled = false;
|
|
drcEnabled = false;
|
|
|
|
//! allocate MEM2 command buffer memory
|
|
gx2CommandBuffer = MEM2_alloc(GX2_COMMAND_BUFFER_SIZE, 0x40);
|
|
|
|
//! initialize GX2 command buffer
|
|
uint32_t gx2_init_attributes[9];
|
|
gx2_init_attributes[0] = GX2_INIT_CMD_BUF_BASE;
|
|
gx2_init_attributes[1] = (uint32_t) 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);
|
|
|
|
uint32_t scanBufferSize = 0;
|
|
uint32_t scaleNeeded = 0;
|
|
|
|
int32_t tvScanMode = ((forceTvScanMode >= 0) ? forceTvScanMode : (int32_t) GX2GetSystemTVScanMode());
|
|
int32_t drcScanMode = ((forceDrcScanMode >= 0) ? forceDrcScanMode : (int32_t) GX2GetSystemDRCScanMode());
|
|
|
|
int32_t tvRenderMode;
|
|
uint32_t tvWidth = 0;
|
|
uint32_t 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;
|
|
}
|
|
|
|
int32_t tvAAMode = GX2_AA_MODE1X;
|
|
int32_t drcAAMode = GX2_AA_MODE4X;
|
|
|
|
//! calculate the scale factor for later texture resize
|
|
widthScaleFactor = 1.0f / (float) tvWidth;
|
|
heightScaleFactor = 1.0f / (float) 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)
|
|
uint32_t 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) {
|
|
uint32_t 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) {
|
|
uint32_t 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 (((uint32_t) tvColorBuffer.aaBuffer & 0xF0000000) == 0xF0000000) {
|
|
MEM1_free(tvColorBuffer.aaBuffer);
|
|
} else {
|
|
MEM2_free(tvColorBuffer.aaBuffer);
|
|
}
|
|
}
|
|
if (drcColorBuffer.aaBuffer) {
|
|
if (((uint32_t) 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);
|
|
}
|