Details of texture cache

April 20, 1995
S.C.E

** Texture cache

When drawing polygons for texture mapping, it is necessary to read
texture patterns on the frame buffer once. Because of that, drawing
speed will decrease with increasing cycles. Since PlayStation
contains the texture cache inside, polygons can be drawn without
the access to the frame buffer if the texture patterns exist in
the cache.

Depending on the texture modes, the texture cache can contain
rectangular area sizes as follows:

                        =====================
                           mode        size
                        ---------------------
                           4 bit      64x64
                           8 bit      32x64
                          16 bit      32x32
                        ---------------------

If the drawing speed is rated approximately, focus only on the
texture cache size when creating data.

If the drawing speed should be tuned up, a precise knowledge of
the cache is required. For the power users the explanations on
the details are as described below.

It is unnecessary to read the following explanations if
applications has a problem that calculation function (by CPU),
compared with drawing function (by GPU), is a bottleneck, or if
the applications don't make use of texture mapping.



**Cache block

A texture page is divided into rectangular areas, each of which
is a unit of the cache size, and managed. Each unit is called a cache
block. The cache blocks have sequential numbers (block numbers).
The cache block structure and the block number in the 4-bit mode are
as follows:

One cache block size is 64x64.
One texture page has 16 blocks.

                  0     64    128   192   255
                      +-----------------------+
                      | 0   | 1   | 2   | 3   |
                      |     |     |     |     |
                  64  |-----+-----+-----+-----|
                      | 4   | 5   | 6   | 7   |
                      |     |     |     |     |
                  128 |-----+-----+-----+-----|
                      | 8   | 9   | 10  | 11  |
                      |     |     |     |     |
                  192 |-----+-----+-----+-----|
                      | 12  | 13  | 14  | 15  |
                      |     |     |     |     |
                  255 +-----------------------+


**Cache entry

A cache block is divided into small areas called cache entries,
whose each size is 16x1. The cache entry structure in the 4-bit mode
is as follows:

One cache block has 256 entries.

                     0  16    32    48    63
                      +-----------------------+
                   0  | 0   | 1   | 2   | 3   |
                      |-----+-----+-----+-----|
                   1  | 4   | 5   | 6   | 7   |
                      |-----+-----+-----+-----|
                      .     .     .     .     .
                      .     .     .     .     .
                      |-----+-----+-----+-----|
                   61 | 244 | 245 | 246 | 247 |
                      |-----+-----+-----+-----|
                   62 | 248 | 249 | 250 | 251 |
                      |-----+-----+-----+-----|
                   63 | 252 | 253 | 254 | 255 |
                      +-----------------------+

Each entry contains the following structure.

struct 
{
  unsigned char block_id;   /* block number tag */
  unsigned short data[4];   /*texture pattern data */
} 
Entry;

typedef Cache Entry[256];

Since the size of the texture pattern data member is 8 bytes, 16
texture pixels are stored in a entry in the 4-bit texture.

**Cache strategy

Each entry has a block number tag, which is used for finding a
hit on the cache.
Using this number, whether the texture pixels (u,v) for texture
mapping exist on the cache or not can be seen.



The block number for a pixel (u,v) can be calculated as below:

(v>>6)<<2 + (u>>6)

The entry number for a pixel (u,v) can be calculated as below:

(v&0x3f)<<2 + (u&0x3f)>>4

Based on these expressions, a hit judgment in the cache is as
described below:

int is_cache_hit_4bit(u_char u, u_char v)
{
  int block_id = (v>>6)<<2 + (u>>6);
  int entry_id = (v&0x3f)<<2 + (u&0x3f)>>4;

  if (Entry[entry_id].block_id == block_id)
    return(1); /* hit in the cache */
  else
    return(0); /* no-hit in the cache */
}



Each cache entry contains individual cache block number.
Therefore, the texture pixels with different entry numbers
can coexist if they have different block numbers.

Example 1
(u,v) = (0,0)-(63,63)

In this rectangular area, all texture pixels belong to the same
texture block. Therefore, the pixels can coexist.

Example 2
(u,v) = (16,16)-(79,79)

In this rectangular area, texture pixels spread over several texture
blocks. However, the pixels can exist together on the cache because
there are no duplicate entries.

Example 3
(u,v) = (8,8)-(71,71)

In this rectangular area, some texture pixels have duplicate entry
numbers.
(for example, (u,v) = (8,8)-(15,8) and (u,v) = (64,8)-(71,8))
Although the rectangular area is smaller than 64x64, they cannot
coexist on the cache.

If no entries are overlapped, separated rectangular areas as
described below can exist on the cache together.

(u,v) = ( 0, 0)-(15,15)
(u,v) = (80,64)-(95,79)


**Differences in modes

Cache block size and cache entry size depend on the texture modes.
The number of entries is 256 in any mode.


========================================================
mode      block    block number   entry   entry number
--------+--------+--------------+-------+---------------
 4      | 64x64  |  16          |  16x1 |  256
 8      | 32x64  |  32          |  8x1  |  256
 16     | 32x32  |  64          |  4x1  |  256
--------+--------+--------------+-------+---------------

