Skip to content

Commit

Permalink
UPBGE: Refactor rasterizer off screen management.
Browse files Browse the repository at this point in the history
Previously a C++ wrapper of GPUOffScreen was in RAS_OpenGLRasterizer but only for
the list of off screen the rasterizer is using. This wrapper was hidden and its
function were wrapped into other RAS_OpenGLRasterizer function.

This behaviour introducing a big time per modifications due to wrapper levels.
To remove one wrapper level the GPUOffScreen is wrapped in a new class named
RAS_OffScreen. This class is reused in ImageRender and in the rest of
RAS_OpenGLRasterizer::OffScreen which is now only owning the RAS_OffScreen
instances and allocating/deleting them. Thes function for allocation are yet
wrapped in the rasterizer under UpdateOffScreen and GetOffScreen. This last function
returns a RAS_OffScreen pointer.
For the other function executing off screen draw, they are let in the rasterizer
because they request use shader interface only owned by the rasterizer.

As the render mechanisme is based on off screen ping-pong, we was only using
off screen index/type, but know that we have acces to RAS_OffScreen it simplify some
code case. But in the place where we have to know what is the next off screen
using the functions Next[Filter/Eye/Render]OffScreen the off screen type/index
is get thanks to the function RAS_OffScreen::GetType(). This function is returning
the value of the type passed as second argument of the constructor.
As ImageRender are now using RAS_OffScreen, the type is then RAS_OFFSCREEN_CUSTOM.

About RAS_OffScreen, the GPUOffScreen is owned by this class and some of its
functions are wrapped. There are functions to bind/unbind color/depth texture,
mipmap, get datas, restore screen. The last bound off screen is set into the
static variable lastOffScreen accesible through RAS_OffScreen::GetLastOffScreen.
  • Loading branch information
panzergame committed Jan 30, 2017
1 parent cf01b56 commit aa4b6a0
Show file tree
Hide file tree
Showing 19 changed files with 480 additions and 428 deletions.
3 changes: 2 additions & 1 deletion source/gameengine/Ketsji/KX_CubeMapManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ void KX_CubeMapManager::RenderCubeMap(RAS_IRasterizer *rasty, KX_CubeMap *cubeMa

// Now the objects are culled and we can render the scene.
m_scene->GetWorldInfo()->RenderBackground(rasty);
m_scene->RenderBuckets(trans, rasty);
// Send a NULL off screen because we use a set of FBO with shared textures, not an off screen.
m_scene->RenderBuckets(trans, rasty, NULL);
}

cubeMap->EndRender();
Expand Down
76 changes: 45 additions & 31 deletions source/gameengine/Ketsji/KX_KetsjiEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "RAS_Rect.h"
#include "RAS_IRasterizer.h"
#include "RAS_ICanvas.h"
#include "RAS_OffScreen.h"
#include "RAS_ILightObject.h"
#include "MT_Vector3.h"
#include "MT_Transform.h"
Expand Down Expand Up @@ -540,8 +541,18 @@ void KX_KetsjiEngine::Render()

// Update all off screen to the current canvas size.
m_rasterizer->UpdateOffScreens(m_canvas);

// The current bound off screen types.
RAS_IRasterizer::OffScreenType ofsTypes[] = {
RAS_IRasterizer::RAS_OFFSCREEN_EYE_LEFT0,
RAS_IRasterizer::RAS_OFFSCREEN_EYE_RIGHT0,
RAS_IRasterizer::RAS_OFFSCREEN_RENDER
};

// Current off screen used for bucket rendering.
RAS_OffScreen *offScreen = m_rasterizer->GetOffScreen(ofsTypes[2]);
// Bind render off screen as default.
m_rasterizer->BindOffScreen(RAS_IRasterizer::RAS_OFFSCREEN_RENDER);
offScreen->Bind();

// clear the entire game screen with the border color
// only once per frame
Expand All @@ -564,9 +575,6 @@ void KX_KetsjiEngine::Render()

const unsigned short numeyepass = (stereomode != RAS_IRasterizer::RAS_STEREO_NOSTEREO) ? 2 : 1;

// The current bound eye off screen if we are using per eye stereo.
int eyefboindex[2] = {RAS_IRasterizer::RAS_OFFSCREEN_EYE_LEFT0, RAS_IRasterizer::RAS_OFFSCREEN_EYE_RIGHT0};

// Used to detect when a camera is the first rendered an then doesn't request a depth clear.
unsigned short pass = 0;

Expand All @@ -591,7 +599,8 @@ void KX_KetsjiEngine::Render()

// Choose unique off screen per eyes in case of stereo.
if (renderpereye) {
m_rasterizer->BindOffScreen(eyefboindex[eyepass]);
offScreen = m_rasterizer->GetOffScreen(ofsTypes[eyepass]);
offScreen->Bind();
// Clear eye off screen only before the first scene render.
if (firstscene) {
m_rasterizer->Clear(RAS_IRasterizer::RAS_COLOR_BUFFER_BIT | RAS_IRasterizer::RAS_DEPTH_BUFFER_BIT);
Expand All @@ -601,41 +610,41 @@ void KX_KetsjiEngine::Render()
// Avoid drawing the scene with the active camera twice when its viewport is enabled
if (activecam && !activecam->GetViewport()) {
// do the rendering
RenderFrame(scene, activecam, pass++);
RenderFrame(scene, activecam, offScreen, pass++);
}

// Draw the scene once for each camera with an enabled viewport
for (CListValue::iterator<KX_Camera> it = cameras->GetBegin(), end = cameras->GetEnd(); it != end; ++it) {
KX_Camera *cam = *it;
if (cam->GetViewport()) {
// do the rendering
RenderFrame(scene, cam, pass++);
RenderFrame(scene, cam, offScreen, pass++);
}
}

// Process filters per eye off screen.
if (renderpereye) {
int target;
if (m_rasterizer->GetOffScreenSamples(eyefboindex[eyepass]) > 0) {
RAS_IRasterizer::OffScreenType target;
if (offScreen->GetSamples() > 0) {
/* Only RAS_OFFSCREEN_EYE_[LEFT/RIGHT]0 has possible multisamples so we target
* RAS_OFFSCREEN_EYE_[LEFT/RIGHT]1 if it's the last scene. */
if (lastscene) {
target = RAS_IRasterizer::NextEyeOffScreen(eyefboindex[eyepass]);
target = RAS_IRasterizer::NextEyeOffScreen(ofsTypes[eyepass]);
}
/* In case of multisamples and filters we're sure that a blit to RAS_OFFSCREEN_FILTER0
* will be done so we can target the same off screen than in input of the filter prossesing. */
* will be done so we can target the same off screen than in input of the filter processing. */
else {
target = eyefboindex[eyepass];
target = ofsTypes[eyepass];
}
}
else {
target = RAS_IRasterizer::NextEyeOffScreen(eyefboindex[eyepass]);
target = RAS_IRasterizer::NextEyeOffScreen(ofsTypes[eyepass]);
}

PostRenderScene(scene, target);

// Render filters and get output off screen.
offScreen = PostRenderScene(scene, offScreen, m_rasterizer->GetOffScreen(target));
// If no filter was rendered the current used off screen can be unchanged.
eyefboindex[eyepass] = m_rasterizer->GetCurrentOffScreenIndex();
ofsTypes[eyepass] = offScreen->GetType();
}
}

Expand All @@ -644,39 +653,41 @@ void KX_KetsjiEngine::Render()
/* Choose final render off screen target. If the current off screen is using multisamples we
* are sure that it will be copied to a non-multisamples off screen before render the filters.
* In this case the targeted off screen is the same as the current off screen. */
int target;
const short fboindex = m_rasterizer->GetCurrentOffScreenIndex();
if (m_rasterizer->GetOffScreenSamples(fboindex) > 0) {
RAS_IRasterizer::OffScreenType target;
if (offScreen->GetSamples() > 0) {
/* If the last scene is rendered it's useless to specify a multisamples off screen, we use then
* RAS_OFFSCREEN_FINAL and avoid an extra off screen blit. */
if (lastscene) {
// Equivalent to RAS_IRasterizer::NextRenderOffScreen(fboindex).
// Equivalent to RAS_IRasterizer::NextRenderOffScreen(ofsTypes[2]).
target = RAS_IRasterizer::RAS_OFFSCREEN_FINAL;
}
else {
target = fboindex;
target = ofsTypes[2];
}
}
/* In case of non-multisamples a ping pong per scene render is made between RAS_OFFSCREEN_RENDER
* and RAS_OFFSCREEN_FINAL. */
else {
target = RAS_IRasterizer::NextRenderOffScreen(fboindex);
target = RAS_IRasterizer::NextRenderOffScreen(ofsTypes[2]);
}

PostRenderScene(scene, target);
// Render filters and get output off screen.
offScreen = PostRenderScene(scene, offScreen, m_rasterizer->GetOffScreen(target));
ofsTypes[2] = offScreen->GetType();
}
}

m_canvas->SetViewPort(0, 0, width, height);

// Compositing per eye off screens to screen.
if (renderpereye) {
m_rasterizer->DrawStereoOffScreen(m_canvas, eyefboindex[RAS_IRasterizer::RAS_STEREO_LEFTEYE], eyefboindex[RAS_IRasterizer::RAS_STEREO_RIGHTEYE]);
RAS_OffScreen *leftofs = m_rasterizer->GetOffScreen(ofsTypes[RAS_IRasterizer::RAS_STEREO_LEFTEYE]);
RAS_OffScreen *rightofs = m_rasterizer->GetOffScreen(ofsTypes[RAS_IRasterizer::RAS_STEREO_RIGHTEYE]);
m_rasterizer->DrawStereoOffScreen(m_canvas, leftofs, rightofs);
}
// Else simply draw the off screen to screen.
else {
const short fboindex = m_rasterizer->GetCurrentOffScreenIndex();
m_rasterizer->DrawOffScreen(m_canvas, fboindex);
m_rasterizer->DrawOffScreen(m_canvas, m_rasterizer->GetOffScreen(ofsTypes[2]));
}

EndFrame();
Expand Down Expand Up @@ -838,7 +849,8 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)

/* render */
m_rasterizer->Clear(RAS_IRasterizer::RAS_DEPTH_BUFFER_BIT | RAS_IRasterizer::RAS_COLOR_BUFFER_BIT);
scene->RenderBuckets(camtrans, m_rasterizer);
// Send a NULL off screen because the viewport is binding it's using its own private one.
scene->RenderBuckets(camtrans, m_rasterizer, NULL);

/* unbind framebuffer object, restore drawmode, free camera */
raslight->UnbindShadowBuffer();
Expand Down Expand Up @@ -931,7 +943,7 @@ const MT_Matrix4x4& KX_KetsjiEngine::GetCameraProjectionMatrix(KX_Scene *scene,
}

// update graphics
void KX_KetsjiEngine::RenderFrame(KX_Scene *scene, KX_Camera *cam, unsigned short pass)
void KX_KetsjiEngine::RenderFrame(KX_Scene *scene, KX_Camera *cam, RAS_OffScreen *offScreen, unsigned short pass)
{
RAS_Rect viewport, area;

Expand Down Expand Up @@ -1013,7 +1025,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene *scene, KX_Camera *cam, unsigned shor
scene->RunDrawingCallbacks(KX_Scene::PRE_DRAW, cam);
#endif

scene->RenderBuckets(camtrans, m_rasterizer);
scene->RenderBuckets(camtrans, m_rasterizer, offScreen);

if (scene->GetPhysicsEnvironment())
scene->GetPhysicsEnvironment()->DebugDrawWorld();
Expand All @@ -1022,7 +1034,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene *scene, KX_Camera *cam, unsigned shor
/*
* To run once per scene
*/
void KX_KetsjiEngine::PostRenderScene(KX_Scene *scene, unsigned short target)
RAS_OffScreen *KX_KetsjiEngine::PostRenderScene(KX_Scene *scene, RAS_OffScreen *inputofs, RAS_OffScreen *targetofs)
{
KX_SetActiveScene(scene);

Expand All @@ -1034,7 +1046,7 @@ void KX_KetsjiEngine::PostRenderScene(KX_Scene *scene, unsigned short target)
m_rasterizer->SetViewport(0, 0, width + 1, height + 1);
m_rasterizer->SetScissor(0, 0, width + 1, height + 1);

scene->Render2DFilters(m_rasterizer, m_canvas, target);
RAS_OffScreen *offScreen = scene->Render2DFilters(m_rasterizer, m_canvas, inputofs, targetofs);

#ifdef WITH_PYTHON
PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
Expand All @@ -1046,6 +1058,8 @@ void KX_KetsjiEngine::PostRenderScene(KX_Scene *scene, unsigned short target)
// Python draw callback can also call debug draw functions, so we have to clear debug shapes.
m_rasterizer->FlushDebugShapes(scene);
#endif

return offScreen;
}

void KX_KetsjiEngine::StopEngine()
Expand Down
5 changes: 3 additions & 2 deletions source/gameengine/Ketsji/KX_KetsjiEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class KX_ISceneConverter;
class KX_NetworkMessageManager;
class CListValue;
class RAS_ICanvas;
class RAS_OffScreen;
class RAS_IRasterizer;
class SCA_IInputDevice;

Expand Down Expand Up @@ -227,8 +228,8 @@ class KX_KetsjiEngine
/// Update and return the projection matrix of a camera depending on the viewport.
const MT_Matrix4x4& GetCameraProjectionMatrix(KX_Scene *scene, KX_Camera *cam, const RAS_Rect& viewport, const RAS_Rect& area);

void RenderFrame(KX_Scene *scene, KX_Camera *cam, unsigned short pass);
void PostRenderScene(KX_Scene *scene, unsigned short target);
void RenderFrame(KX_Scene *scene, KX_Camera *cam, RAS_OffScreen *offScreen, unsigned short pass);
RAS_OffScreen *PostRenderScene(KX_Scene *scene, RAS_OffScreen *inputofs, RAS_OffScreen *targetofs);
void RenderDebugProperties();
/// Debug draw cameras frustum of a scene.
void DrawDebugCameraFrustum(KX_Scene *scene, const RAS_Rect& viewport, const RAS_Rect& area);
Expand Down
9 changes: 4 additions & 5 deletions source/gameengine/Ketsji/KX_Scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1701,16 +1701,15 @@ RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat, bool



void KX_Scene::RenderBuckets(const MT_Transform & cameratransform,
class RAS_IRasterizer* rasty)
void KX_Scene::RenderBuckets(const MT_Transform& cameratransform, RAS_IRasterizer *rasty, RAS_OffScreen *offScreen)
{
for (CListValue::iterator<KX_GameObject> it = m_objectlist->GetBegin(), end = m_objectlist->GetEnd(); it != end; ++it) {
/* This function update all mesh slot info (e.g culling, color, matrix) from the game object.
* It's done just before the render to be sure of the object color and visibility. */
(*it)->UpdateBuckets();
}

m_bucketmanager->Renderbuckets(cameratransform,rasty);
m_bucketmanager->Renderbuckets(cameratransform, rasty, offScreen);
KX_BlenderMaterial::EndFrame(rasty);
}

Expand Down Expand Up @@ -2083,9 +2082,9 @@ RAS_2DFilterManager *KX_Scene::Get2DFilterManager() const
return m_filterManager;
}

void KX_Scene::Render2DFilters(RAS_IRasterizer *rasty, RAS_ICanvas *canvas, unsigned short target)
RAS_OffScreen *KX_Scene::Render2DFilters(RAS_IRasterizer *rasty, RAS_ICanvas *canvas, RAS_OffScreen *inputofs, RAS_OffScreen *targetofs)
{
m_filterManager->RenderFilters(rasty, canvas, target);
return m_filterManager->RenderFilters(rasty, canvas, inputofs, targetofs);
}

#ifdef WITH_PYTHON
Expand Down
7 changes: 3 additions & 4 deletions source/gameengine/Ketsji/KX_Scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class RAS_BucketManager;
class RAS_MaterialBucket;
class RAS_IPolyMaterial;
class RAS_IRasterizer;
class RAS_IRenderTools;
class RAS_OffScreen;
class RAS_2DFilterManager;
class KX_2DFilterManager;
class SCA_JoystickManager;
Expand Down Expand Up @@ -318,8 +318,7 @@ class KX_Scene : public CValue, public SCA_IScene
KX_CubeMapManager *GetCubeMapManager();
RAS_BoundingBoxManager *GetBoundingBoxManager();
RAS_MaterialBucket* FindBucket(RAS_IPolyMaterial* polymat, bool &bucketCreated);
void RenderBuckets(const MT_Transform& cameratransform,
RAS_IRasterizer* rasty);
void RenderBuckets(const MT_Transform& cameratransform, RAS_IRasterizer *rasty, RAS_OffScreen *offScreen);
void RenderCubeMaps(RAS_IRasterizer *rasty);

/**
Expand Down Expand Up @@ -544,7 +543,7 @@ class KX_Scene : public CValue, public SCA_IScene
* 2D Filters
*/
RAS_2DFilterManager *Get2DFilterManager() const;
void Render2DFilters(RAS_IRasterizer *rasty, RAS_ICanvas *canvas, unsigned short target);
RAS_OffScreen *Render2DFilters(RAS_IRasterizer *rasty, RAS_ICanvas *canvas, RAS_OffScreen *inputofs, RAS_OffScreen *targetofs);

KX_ObstacleSimulation* GetObstacleSimulation() { return m_obstacleSimulation; }

Expand Down
12 changes: 7 additions & 5 deletions source/gameengine/Rasterizer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ set(SRC
RAS_2DFilterData.cpp
RAS_2DFilterManager.cpp
RAS_BatchGroup.cpp
RAS_BoundingBox.cpp
RAS_BoundingBoxManager.cpp
RAS_BucketManager.cpp
RAS_CubeMap.cpp
RAS_DisplayArrayBucket.cpp
Expand All @@ -64,11 +66,10 @@ set(SRC
RAS_IPolygonMaterial.cpp
RAS_ITexVert.cpp
RAS_MaterialBucket.cpp
RAS_BoundingBox.cpp
RAS_BoundingBoxManager.cpp
RAS_MeshObject.cpp
RAS_MeshSlot.cpp
RAS_MeshUser.cpp
RAS_OffScreen.cpp
RAS_Polygon.cpp
RAS_Shader.cpp
RAS_Texture.cpp
Expand All @@ -77,13 +78,15 @@ set(SRC
RAS_2DFilterData.h
RAS_2DFilter.h
RAS_2DFilterManager.h
RAS_BatchDisplayArray.h
RAS_BatchGroup.h
RAS_BoundingBox.h
RAS_BoundingBoxManager.h
RAS_BucketManager.h
RAS_CameraData.h
RAS_CubeMap.h
RAS_Deformer.h
RAS_DisplayArray.h
RAS_BatchDisplayArray.h
RAS_DisplayArrayBucket.h
RAS_FramingManager.h
RAS_ICanvas.h
Expand All @@ -97,12 +100,11 @@ set(SRC
RAS_ISync.h
RAS_ITexVert.h
RAS_MaterialBucket.h
RAS_BoundingBox.h
RAS_BoundingBoxManager.h
RAS_MeshMaterial.h
RAS_MeshObject.h
RAS_MeshSlot.h
RAS_MeshUser.h
RAS_OffScreen.h
RAS_Polygon.h
RAS_Rect.h
RAS_Shader.h
Expand Down
Loading

0 comments on commit aa4b6a0

Please sign in to comment.