I have now tested this (look further down in this post), and it works.
The geometry is clipped, since you do not pass in what type of primitive you test against, it could not know how to rasterize it.
On big strength of this that I see is that you could pre-record a scene and then just play it back culled and ready with no cpu-involvement. You could also use it to switch between two different lod-levels using only the GPU.
One thing to think about if you're doing the implementation is that while inside a conditional rendering, you do not know if a matrix has been flushed to the system. I got bitten by this while doing the tests, and debugged for 15 minutes until I realised that the matrix in question had been flushed by Gum inside the conditional region and didn't update again since it wasn't pushed (while the library thought it was), so make your stack culling-aware. :)
Here's a patch for the cube-sample that show hardware culling in action:
Code: Select all
Index: cube.c
===================================================================
--- cube.c (revision 1707)
+++ cube.c (working copy)
@@ -11,6 +11,7 @@
#include <pspdebug.h>
#include <stdlib.h>
#include <stdio.h>
+#include <pspctrl.h>
#include <math.h>
#include <string.h>
@@ -20,7 +21,7 @@
#include "../common/callbacks.h"
#include "../common/vram.h"
-PSP_MODULE_INFO("Cube Sample", 0, 1, 1);
+PSP_MODULE_INFO("Hardware Culling Sample", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER);
static unsigned int __attribute__((aligned(16))) list[262144];
@@ -122,17 +123,35 @@
sceDisplayWaitVblankStart();
sceGuDisplay(GU_TRUE);
+ sceCtrlSetSamplingCycle(0);
+ sceCtrlSetSamplingMode(0);
+
// run sample
int val = 0;
+ float x = 0;
+ float y = 0;
while(running())
{
sceGuStart(GU_DIRECT,list);
+ SceCtrlData pad;
+ if (sceCtrlPeekBufferPositive(&pad,1))
+ {
+ if (pad.Buttons & PSP_CTRL_UP)
+ y += 0.1f;
+ if (pad.Buttons & PSP_CTRL_DOWN)
+ y -= 0.1f;
+ if (pad.Buttons & PSP_CTRL_LEFT)
+ x -= 0.1f;
+ if (pad.Buttons & PSP_CTRL_RIGHT)
+ x += 0.1f;
+ }
+
// clear screen
- sceGuClearColor(0xff554433);
+ sceGuClearColor(0x554400|(128 + (int)(cosf(val * (GU_PI/180.0f)) * 127.0f)));
sceGuClearDepth(0);
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
@@ -143,17 +162,38 @@
sceGumPerspective(75.0f,16.0f/9.0f,0.5f,1000.0f);
sceGumMatrixMode(GU_VIEW);
- sceGumLoadIdentity();
-
- sceGumMatrixMode(GU_MODEL);
- sceGumLoadIdentity();
{
- ScePspFVector3 pos = { 0, 0, -2.5f };
+ ScePspFVector3 pos = { x, y, -2.5f };
ScePspFVector3 rot = { val * 0.79f * (GU_PI/180.0f), val * 0.98f * (GU_PI/180.0f), val * 1.32f * (GU_PI/180.0f) };
+ sceGumLoadIdentity();
sceGumTranslate(&pos);
sceGumRotateXYZ(&rot);
}
+ sceGumMatrixMode(GU_MODEL);
+ {
+ ScePspFVector3 scale = { 0.1f, 0.1f, 0.1f };
+ sceGumLoadIdentity();
+ sceGumScale(&scale);
+ }
+
+ {
+ ScePspFVector3 scale = { 0.3f, 0.3f, 0.3f };
+ sceGumMatrixMode(GU_MODEL);
+ sceGumLoadIdentity();
+ sceGumScale(&scale);
+ }
+
+ // begin conditional rendering
+
+ sceGumUpdateMatrix(); // note, not a sceGum*-function, so the matrices has to be flushed manually (got bitten by that one :))
+ sceGuBeginObject(GU_TEXTURE_32BITF|GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D,12*3,0,vertices);
+
+ /// ALL BELOW THIS LINE IS ONLY RENDERED WHILE THE SMALLER CUBE IS INSIDE THE FRUSTUM
+
+ sceGumMatrixMode(GU_MODEL);
+ sceGumLoadIdentity();
+
// setup texture
sceGuTexMode(GU_PSM_4444,0,0,0);
@@ -169,6 +209,29 @@
sceGumDrawArray(GU_TRIANGLES,GU_TEXTURE_32BITF|GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D,12*3,0,vertices);
+ /// ALL ABOVE THIS LINE IS ONLY RENDERED WHILE THE SMALLER CUBE IS INSIDE THE FRUSTUM
+
+ // end conditional rendering
+
+ sceGuEndObject();
+
+ // draw line-cube to overlay (just for showing bound)
+ {
+ ScePspFVector3 scale = { 0.3f, 0.3f, 0.3f };
+ sceGumMatrixMode(GU_MODEL);
+ sceGumLoadIdentity();
+ sceGumScale(&scale);
+
+ sceGuEnable(GU_LIGHTING);
+ sceGuModelColor(0xffffff,0,0,0);
+ sceGuDisable(GU_TEXTURE_2D);
+ sceGuDepthFunc(GU_ALWAYS);
+ sceGumDrawArray(GU_LINE_STRIP,GU_TEXTURE_32BITF|GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D,12*3,0,vertices);
+ sceGuDepthFunc(GU_GEQUAL);
+ sceGuEnable(GU_TEXTURE_2D);
+ sceGuDisable(GU_LIGHTING);
+ }
+
sceGuFinish();
sceGuSync(0,0);
Index: Makefile.sample
===================================================================
--- Makefile.sample (revision 1707)
+++ Makefile.sample (working copy)
@@ -8,7 +8,7 @@
LIBDIR =
LDFLAGS =
-LIBS= -lpspgum -lpspgu -lm
+LIBS= -lpspgum -lpspgu -lm -lpspctrl
EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = Cube Sample
I test a smaller version of the cube against the frustum and then only render the big one if it is visible. Move the cube with the dpad.