r300g: Always emit scissors.
[mesa.git] / src / gallium / drivers / r300 / r300_texture.c
index 7ea4c33fa9a3366575e296e94444db624da9b7e6..2784916ddf4dd36c86cb2b42e9c85b3cb5a24a56 100644 (file)
  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  * USE OR OTHER DEALINGS IN THE SOFTWARE. */
 
+#include "pipe/p_screen.h"
+
+#include "util/u_format.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#include "r300_context.h"
 #include "r300_texture.h"
+#include "r300_screen.h"
 
-static void r300_setup_texture_state(struct r300_texture* tex)
+static void r300_setup_texture_state(struct r300_texture* tex, boolean is_r500)
 {
     struct r300_texture_state* state = &tex->state;
     struct pipe_texture *pt = &tex->tex;
 
-    state->format0 = R300_TX_WIDTH((pt->width[0] - 1) & 0x7ff) |
-        R300_TX_HEIGHT((pt->height[0] - 1) & 0x7ff) |
-        R300_TX_DEPTH(util_logbase2(pt->depth[0]) & 0xf) |
-        R300_TX_NUM_LEVELS(pt->last_level) |
-        R300_TX_PITCH_EN;
+    state->format0 = R300_TX_WIDTH((pt->width0 - 1) & 0x7ff) |
+                     R300_TX_HEIGHT((pt->height0 - 1) & 0x7ff);
+
+    if (tex->is_npot) {
+        /* rectangles love this */
+        state->format0 |= R300_TX_PITCH_EN;
+        state->format2 = (tex->pitch[0] - 1) & 0x1fff;
+    } else {
+        /* power of two textures (3D, mipmaps, and no pitch) */
+        state->format0 |= R300_TX_DEPTH(util_logbase2(pt->depth0) & 0xf);
+    }
 
-    /* XXX */
     state->format1 = r300_translate_texformat(pt->format);
     if (pt->target == PIPE_TEXTURE_CUBE) {
-       state->format1 |= R300_TX_FORMAT_CUBIC_MAP;
+        state->format1 |= R300_TX_FORMAT_CUBIC_MAP;
     }
     if (pt->target == PIPE_TEXTURE_3D) {
-       state->format1 |= R300_TX_FORMAT_3D;
+        state->format1 |= R300_TX_FORMAT_3D;
     }
 
-    state->format2 = (r300_texture_get_stride(tex, 0) / pt->block.size) - 1;
-
-    /* Assume (somewhat foolishly) that oversized textures will
-     * not be permitted by the state tracker. */
-    if (pt->width[0] > 2048) {
-        state->format2 |= R500_TXWIDTH_BIT11;
-    }
-    if (pt->height[0] > 2048) {
-        state->format2 |= R500_TXHEIGHT_BIT11;
+    /* large textures on r500 */
+    if (is_r500)
+    {
+        if (pt->width0 > 2048) {
+            state->format2 |= R500_TXWIDTH_BIT11;
+        }
+        if (pt->height0 > 2048) {
+            state->format2 |= R500_TXHEIGHT_BIT11;
+        }
     }
+    assert(is_r500 || (pt->width0 <= 2048 && pt->height0 <= 2048));
 
     debug_printf("r300: Set texture state (%dx%d, %d levels)\n",
-                pt->width[0], pt->height[0], pt->last_level);
+                pt->width0, pt->height0, pt->last_level);
+}
+
+unsigned r300_texture_get_offset(struct r300_texture* tex, unsigned level,
+                                 unsigned zslice, unsigned face)
+{
+    unsigned offset = tex->offset[level];
+
+    switch (tex->tex.target) {
+        case PIPE_TEXTURE_3D:
+            assert(face == 0);
+            return offset + zslice * tex->layer_size[level];
+
+        case PIPE_TEXTURE_CUBE:
+            assert(zslice == 0);
+            return offset + face * tex->layer_size[level];
+
+        default:
+            assert(zslice == 0 && face == 0);
+            return offset;
+    }
 }
 
 /**
@@ -67,47 +101,51 @@ unsigned r300_texture_get_stride(struct r300_texture* tex, unsigned level)
         return tex->stride_override;
 
     if (level > tex->tex.last_level) {
-        debug_printf("%s: level (%u) > last_level (%u)\n", __FUNCTION__, level, tex->tex.last_level);
+        debug_printf("%s: level (%u) > last_level (%u)\n", __FUNCTION__,
+            level, tex->tex.last_level);
         return 0;
     }
 
-    return align(pf_get_stride(&tex->tex.block, tex->tex.width[level]), 32);
+    return align(util_format_get_stride(tex->tex.format, u_minify(tex->tex.width0, level)), 32);
 }
 
 static void r300_setup_miptree(struct r300_texture* tex)
 {
     struct pipe_texture* base = &tex->tex;
-    int stride, size;
+    int stride, size, layer_size;
     int i;
 
-    for (i = 0; i <= base->last_level; i++) {
-        if (i > 0) {
-            base->width[i] = minify(base->width[i-1]);
-            base->height[i] = minify(base->height[i-1]);
-            base->depth[i] = minify(base->depth[i-1]);
-        }
+    debug_printf("r300: Making miptree for texture, format %s\n", pf_name(base->format));
 
-        base->nblocksx[i] = pf_get_nblocksx(&base->block, base->width[i]);
-        base->nblocksy[i] = pf_get_nblocksy(&base->block, base->height[i]);
+    for (i = 0; i <= base->last_level; i++) {
+        unsigned nblocksy = util_format_get_nblocksy(base->format, u_minify(base->height0, i));
 
-        /* Radeons enjoy things in multiples of 64.
-         *
-         * XXX
-         * POT, uncompressed, unmippmapped textures can be aligned to 32,
-         * instead of 64. */
         stride = r300_texture_get_stride(tex, i);
-        size = stride * base->nblocksy[i] * base->depth[i];
+        layer_size = stride * nblocksy;
+
+        if (base->target == PIPE_TEXTURE_CUBE)
+            size = layer_size * 6;
+        else
+            size = layer_size * u_minify(base->depth0, i);
 
         tex->offset[i] = align(tex->size, 32);
         tex->size = tex->offset[i] + size;
+        tex->layer_size[i] = layer_size;
+        tex->pitch[i] = stride / util_format_get_blocksize(base->format);
 
         debug_printf("r300: Texture miptree: Level %d "
-                "(%dx%dx%d px, pitch %d bytes)\n",
-                i, base->width[i], base->height[i], base->depth[i],
-                stride);
+                "(%dx%dx%d px, pitch %d bytes) %d bytes total\n",
+                i, u_minify(base->width0, i), u_minify(base->height0, i),
+                u_minify(base->depth0, i), stride, tex->size);
     }
 }
 
+static void r300_setup_flags(struct r300_texture* tex)
+{
+    tex->is_npot = !util_is_power_of_two(tex->tex.width0) ||
+                   !util_is_power_of_two(tex->tex.height0);
+}
+
 /* Create a new texture. */
 static struct pipe_texture*
     r300_texture_create(struct pipe_screen* screen,
@@ -123,9 +161,9 @@ static struct pipe_texture*
     pipe_reference_init(&tex->tex.reference, 1);
     tex->tex.screen = screen;
 
+    r300_setup_flags(tex);
     r300_setup_miptree(tex);
-
-    r300_setup_texture_state(tex);
+    r300_setup_texture_state(tex, r300_screen(screen)->caps->is_r500);
 
     tex->buffer = screen->buffer_create(screen, 1024,
                                         PIPE_BUFFER_USAGE_PIXEL,
@@ -159,17 +197,20 @@ static struct pipe_surface* r300_get_tex_surface(struct pipe_screen* screen,
     struct pipe_surface* surface = CALLOC_STRUCT(pipe_surface);
     unsigned offset;
 
-    /* XXX this is certainly dependent on tex target */
-    offset = tex->offset[level];
+    offset = r300_texture_get_offset(tex, level, zslice, face);
 
     if (surface) {
         pipe_reference_init(&surface->reference, 1);
         pipe_texture_reference(&surface->texture, texture);
         surface->format = texture->format;
-        surface->width = texture->width[level];
-        surface->height = texture->height[level];
+        surface->width = u_minify(texture->width0, level);
+        surface->height = u_minify(texture->height0, level);
         surface->offset = offset;
         surface->usage = flags;
+        surface->zslice = zslice;
+        surface->texture = texture;
+        surface->face = face;
+        surface->level = level;
     }
 
     return surface;
@@ -189,10 +230,10 @@ static struct pipe_texture*
 {
     struct r300_texture* tex;
 
-    /* XXX we should start doing mips now... */
+    /* Support only 2D textures without mipmaps */
     if (base->target != PIPE_TEXTURE_2D ||
-        base->last_level != 0 ||
-        base->depth[0] != 1) {
+        base->depth0 != 1 ||
+        base->last_level != 0) {
         return NULL;
     }
 
@@ -206,9 +247,10 @@ static struct pipe_texture*
     tex->tex.screen = screen;
 
     tex->stride_override = *stride;
+    tex->pitch[0] = *stride / util_format_get_blocksize(base->format);
 
-    /* XXX */
-    r300_setup_texture_state(tex);
+    r300_setup_flags(tex);
+    r300_setup_texture_state(tex, r300_screen(screen)->caps->is_r500);
 
     pipe_buffer_reference(&tex->buffer, buffer);
 
@@ -240,10 +282,9 @@ r300_video_surface_create(struct pipe_screen *screen,
     template.target = PIPE_TEXTURE_2D;
     template.format = PIPE_FORMAT_X8R8G8B8_UNORM;
     template.last_level = 0;
-    template.width[0] = util_next_power_of_two(width);
-    template.height[0] = util_next_power_of_two(height);
-    template.depth[0] = 1;
-    pf_get_block(template.format, &template.block);
+    template.width0 = util_next_power_of_two(width);
+    template.height0 = util_next_power_of_two(height);
+    template.depth0 = 1;
     template.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER |
                          PIPE_TEXTURE_USAGE_RENDER_TARGET;