psx.wiki
Log in
Main page
Hardware
Hardware tests
System software
SDKs
File formats
Games
Tools
History
All pages
page
view source
history
View source for GPU Rendering
← GPU Rendering
You do not have permission to edit this page.
Log in
to edit.
--- title: GPU Rendering type: component summary: How the GPU shades, modulates, blends and dithers pixels and orders its drawing. category: Hardware category: GPU --- ## Overview The [GPU](/hardware/gpu/) operates according to polygon drawing instructions from the CPU. The CPU transfers texture images and CLUTs to the frame buffer, and the GPU then draws polygons from the coordinates and color information that the GTE computes.[^hw14] This page describes how the GPU computes the color of each pixel it draws and how a program controls the order of drawing. The command formats are in [GP0 Drawing Commands](/hardware/gpu/gp0-drawing/). ## Shading The GPU scales the color of a primitive to a given brightness. With flat shading one color applies to the whole primitive. With Gouraud shading each vertex has its own color, and the GPU interpolates the colors across the polygon.[^spx-shade][^hw37] ## Texture Modulation In a texture-mapped primitive the r, g and b members of the primitive give the brightness of the texture. The brightness of each drawn pixel is computed from the texel and these members, so that with r, g and b all at 128 the pixels have the same brightness as the source texture. A result above 255 is clipped to 255.[^lo824][^lo825] psx-spx writes the calculation per channel as final = (texel x vertex color) / 128. A vertex color below 128 therefore darkens the texel and one above 128 brightens it, and 808080h leaves the texture unchanged.[^spx-mod] The r, g and b members must be set when a texture-mapping primitive is initialized, or the shading must be turned off with SetShadeTex().[^lo825] In the command word this is the TGE bit, which draws the texture as stored.[^spx-poly] psx-spx reports a difference between GPU versions. The v0 GPU reduces the 8-bit shading color to 5 bits before multiplying, ((color/8) x texel)/2, while the v2 GPU computes (color x texel)/16. Shaded textures on the v0 GPU therefore show coarser steps, which psx-spx compares to the snow scene in the first level of Tomb Raider.[^spx-ver][^spx-shtex] ## Semi-Transparency When a pixel is semi-transparent, the GPU reads the pixel already in the frame buffer and combines it with the new pixel. Processing speed is greatly reduced in this mode, because the existing pixel must be read, processed and written back.[^lo824] The rate is set per primitive, from the texture page, and the same rate applies to primitives without a texture:[^lo824] Table: Semi-transparency rates | ABR | Background brightness value | Primitive brightness value | psx-spx notation | | --- | --- | --- | --- | | 0 | 0.5 | 0.5 | B/2+F/2 | | 1 | 1.0 | 1.0 | B+F | | 2 | 1.0 | -1.0 | B-F | | 3 | 1.0 | 0.25 | B+F/4 | The brightness value is clipped when it exceeds the maximum.[^lo824] psx-spx adds that an additive result above 255 is clamped to 255 and a subtractive result below 0 is clamped to 0. Neither result wraps.[^spx-semi] A primitive without a texture is drawn semi-transparent in every pixel when SetSemiTrans() is applied. A textured primitive is semi-transparent only in texels whose STP bit is set; in 4-bit and 8-bit mode the bit comes from the CLUT entry.[^lo824][^spx-semi] The [frame buffer page](/hardware/gpu/vram/) gives the full table of transparent and semi-transparent texel values. ## Dithering The GPU computes color in 24 bits and dithers the result when it writes 15-bit pixels, so the display comes close to 24-bit color.[^hw34] The dtd flag of DRAWENV turns dithering on, and GP0(E1h) bit 9 holds the setting.[^lo86][^spx-e1] For dithering the frame buffer is divided into 4 x 4 pixel blocks. The offset for the pixel position is added to the 8-bit R, G and B values, the result is saturated to 00h to FFh and then divided by 8, which gives the 5-bit values:[^spx-dith] Table: Dither offsets | Line | Pixel 0 | Pixel 1 | Pixel 2 | Pixel 3 | | --- | --- | --- | --- | --- | | 0 | -4 | +0 | -3 | +1 | | 1 | +2 | -2 | +3 | -1 | | 2 | -3 | +1 | -4 | +0 | | 3 | +3 | -1 | +2 | -2 | Lines 2 and 3 are lines 0 and 1 shifted by two pixels. Polygons are dithered only when they use Gouraud shading or modulation, lines are always dithered, and rectangles are never dithered.[^spx-dith] ## Texture Mapping Distortion The PlayStation uses affine transformation for texture mapping. The texture coordinates (u, v) of a point (x, y) inside a polygon are calculated as u = a0 x + a1 y + a2 and v = b0 x + b1 y + b2. A correct perspective mapping would instead divide by a term in z, u = (a0 x + a1 y + a2 z + a3) / (c0 x + c1 y + c2 z + c3), and likewise for v. The affine result is therefore correct only when the depth inside the polygon is constant or changes little, and a large quadrilateral with a large change of depth shows a bent diagonal line.[^lo831] The GPU receives no Z coordinates from the GTE, so it cannot undo the perspective division for each pixel.[^spx-persp] Sony's FAQ adds that a quadrilateral is drawn as 2 triangles. A texture line across a freely distorted quadrilateral therefore bends at the diagonal. Of the remedies it lists, it recommends dividing the polygon into smaller pieces, although this increases the number of polygons.[^faq11] ## Primitive Division Dividing a large primitive in advance solves most of these problems. For a primitive that may become large, its area and its distance from the viewpoint before perspective conversion are evaluated, and it is divided recursively at the mid-points. Perspective conversion is then correct at each new vertex, and the more division vertices there are, the closer the image comes to a correct mapping.[^lo832][^lo833] Division also helps the texture cache and clipping. The (du, dv) of each piece is smaller than that of the original, and when it fits in the texture cache the drawing efficiency rises greatly. Smaller pieces are also more likely to fall entirely outside the drawing area, which reduces the empty cycles spent on clipped pixels.[^lo833] ## Drawing Order The GPU stores only colors in the frame buffer. It has no depth buffer and handles only X and Y coordinates, so it cannot tell whether a new pixel lies in front of or behind an old one.[^spx-depth] When several primitives are drawn, the order of execution therefore decides the display priority: each primitive is drawn on top of those drawn before it.[^lo812] ### Ordering Tables Libgpu controls the order with an ordering table (OT), an array of pointers to primitives in main memory whose size sets the resolution of the display priority. ClearOTag() turns the array into an empty list of primitives, AddPrim() registers a primitive in one entry, and DrawOTag() executes the whole table. The primitives at the start of the OT are executed first and therefore appear furthest back.[^lo813][^lo814] Primitives registered in the same entry are executed in the reverse order of registration. Special primitives in the table change the drawing environment for the primitives that follow them.[^lo814] Because DrawOTag() is a non-blocking function, the CPU can continue working while the GPU draws.[^lo813] The tag word of each primitive holds the number of GPU words in the packet in its top 8 bits and a pointer to the next primitive in its bottom 24 bits.[^lo811] DMA channel 2 in list mode follows these pointers and sends each packet to GP0. psx-spx gives the setup: wait for GPUSTAT bit 28, enable DMA channel 2, set GP1(04h) to 2, set D2_MADR to the start of the list and D2_BCR to 0, and write 01000401h to D2_CHCR.[^spx-ot] ### Z Sorting An OT implements Z sorting. The position of a primitive in the OT is calculated from its Z value, and many libgte functions such as RotTransPers() return this index, otz, while they transform coordinates. Because otz is the Z coordinate divided by 4, an OT needs only 1/4 of the dynamic range of the actual Z depth.[^lo815] psx-spx notes that the GTE commands AVSZ3 and AVSZ4 average the Z coordinates of 3 or 4 vertices into the GTE register OTZ for this purpose.[^spx-ot] Since otz is large for distant objects and approaches 0 for near ones, it would have to be inverted to index a normal OT. ClearOTagR() instead builds the OT in reverse order, so that AddPrim(ot+otz, ...) can be used directly and DrawOTag(ot+OTSIZE-1) starts at the far end.[^lo815] The reverse OT is cleared by a high-speed hardware function, while the normal OT is cleared by software, so a large reverse OT is initialized much faster.[^lo816] That hardware is DMA channel 6, which writes a list in which each entry points to the previous one and the first entry holds the end code xxFFFFFFh.[^spx-ot] An entire OT can also be inserted into another with AddPrims(). This method is valid for using more than one hierarchical coordinate system at once. The last entry of the inserted OT must not hold a primitive, because its link is replaced.[^lo817] ### Packet Double Buffer The OT and its primitives form the packet buffer. The CPU cannot change a packet buffer until the GPU has finished drawing it, so registering primitives and drawing them cannot overlap with one buffer. Two packet buffers are therefore used: the CPU fills one while the GPU draws the other, and the two exchange roles each frame.[^lo820][^lo821] ## References [^hw14]: Sony Computer Entertainment Inc. PlayStation Hardware. August 1998. Page 1-4. [^hw34]: Sony Computer Entertainment Inc. PlayStation Hardware. August 1998. Page 3-4. [^hw37]: Sony Computer Entertainment Inc. PlayStation Hardware. August 1998. Page 3-7. [^lo86]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-6. [^lo811]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-11. [^lo812]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-12. [^lo813]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-13. [^lo814]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-14. [^lo815]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-15, Table 8-7. [^lo816]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-16. [^lo817]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-17. [^lo820]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-20, Figure 8-8, Figure 8-9. [^lo821]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-21. [^lo824]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-24, Table 8-12. [^lo825]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-25. [^lo831]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-31. [^lo832]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-32. [^lo833]: Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 8-33. [^faq11]: Sony Computer Entertainment. The Un-official PlayStation Development FAQ, LIBGPU Conference. Release v1.1. August 31, 1995. Item 1.1. [^spx-poly]: psx-spx. Graphics Processing Unit (GPU), GPU Render Polygon Commands. https://psx-spx.consoledev.net/graphicsprocessingunitgpu/#gpu-render-polygon-commands [^spx-e1]: psx-spx. Graphics Processing Unit (GPU), GP0(E1h) - Draw Mode setting. https://psx-spx.consoledev.net/graphicsprocessingunitgpu/#gpu-rendering-attributes [^spx-ver]: psx-spx. Graphics Processing Unit (GPU), Summary of GPU Differences. https://psx-spx.consoledev.net/graphicsprocessingunitgpu/#gpu-versions [^spx-shtex]: psx-spx. Graphics Processing Unit (GPU), Shaded Textures. https://psx-spx.consoledev.net/graphicsprocessingunitgpu/#gpu-versions [^spx-depth]: psx-spx. Graphics Processing Unit (GPU), Absent Depth Buffer. https://psx-spx.consoledev.net/graphicsprocessingunitgpu/#gpu-depth-ordering [^spx-ot]: psx-spx. Graphics Processing Unit (GPU), GPU Depth Ordering. https://psx-spx.consoledev.net/graphicsprocessingunitgpu/#gpu-depth-ordering [^spx-persp]: psx-spx. Graphics Processing Unit (GPU), Perspective correct Rendering. https://psx-spx.consoledev.net/graphicsprocessingunitgpu/#gpu-misc [^spx-dith]: psx-spx. Graphics Processing Unit (GPU), 24bit RGB to 15bit RGB Dithering (enabled in texture page attribute). https://psx-spx.consoledev.net/graphicsprocessingunitgpu/#gpu-misc [^spx-shade]: psx-spx. Graphics Processing Unit (GPU), Shading. https://psx-spx.consoledev.net/graphicsprocessingunitgpu/#gpu-misc [^spx-semi]: psx-spx. Graphics Processing Unit (GPU), Semi-transparency. https://psx-spx.consoledev.net/graphicsprocessingunitgpu/#gpu-misc [^spx-mod]: psx-spx. Graphics Processing Unit (GPU), Modulation (also known as Texture Blending). https://psx-spx.consoledev.net/graphicsprocessingunitgpu/#gpu-misc