Browse Source

st/nine: Only update dirty rect for UpdateTexture

UpdateTexture is supposed to optimise by uploading only for the
dirty region of the source (d3d9 doc, wine tests).
This patch adds the behaviour for surfaces, but not entirely for
volumes.

Signed-off-by: Axel Davy <axel.davy@ens.fr>
tags/11.0-branchpoint
Axel Davy 10 years ago
parent
commit
41f54040e2

+ 39
- 8
src/gallium/state_trackers/nine/device9.c View File

@@ -1278,6 +1278,7 @@ NineDevice9_UpdateTexture( struct NineDevice9 *This,
struct NineBaseTexture9 *srcb = NineBaseTexture9(pSourceTexture);
unsigned l, m;
unsigned last_level = dstb->base.info.last_level;
RECT rect;

DBG("This=%p pSourceTexture=%p pDestinationTexture=%p\n", This,
pSourceTexture, pDestinationTexture);
@@ -1303,10 +1304,6 @@ NineDevice9_UpdateTexture( struct NineDevice9 *This,

user_assert(dstb->base.type == srcb->base.type, D3DERR_INVALIDCALL);

/* TODO: We can restrict the update to the dirty portions of the source.
* Yes, this seems silly, but it's what MSDN says ...
*/

/* Find src level that matches dst level 0: */
user_assert(srcb->base.info.width0 >= dstb->base.info.width0 &&
srcb->base.info.height0 >= dstb->base.info.height0 &&
@@ -1330,9 +1327,25 @@ NineDevice9_UpdateTexture( struct NineDevice9 *This,
struct NineTexture9 *dst = NineTexture9(dstb);
struct NineTexture9 *src = NineTexture9(srcb);

for (l = 0; l <= last_level; ++l, ++m)
if (src->dirty_rect.width == 0)
return D3D_OK;

pipe_box_to_rect(&rect, &src->dirty_rect);
for (l = 0; l < m; ++l)
rect_minify_inclusive(&rect);

for (l = 0; l <= last_level; ++l, ++m) {
fit_rect_format_inclusive(dst->base.base.info.format,
&rect,
dst->surfaces[l]->desc.Width,
dst->surfaces[l]->desc.Height);
NineSurface9_CopyMemToDefault(dst->surfaces[l],
src->surfaces[m], NULL, NULL);
src->surfaces[m],
(POINT *)&rect,
&rect);
rect_minify_inclusive(&rect);
}
u_box_origin_2d(0, 0, &src->dirty_rect);
} else
if (dstb->base.type == D3DRTYPE_CUBETEXTURE) {
struct NineCubeTexture9 *dst = NineCubeTexture9(dstb);
@@ -1341,10 +1354,25 @@ NineDevice9_UpdateTexture( struct NineDevice9 *This,

/* GPUs usually have them stored as arrays of mip-mapped 2D textures. */
for (z = 0; z < 6; ++z) {
if (src->dirty_rect[z].width == 0)
continue;

pipe_box_to_rect(&rect, &src->dirty_rect[z]);
for (l = 0; l < m; ++l)
rect_minify_inclusive(&rect);

for (l = 0; l <= last_level; ++l, ++m) {
NineSurface9_CopyMemToDefault(dst->surfaces[l * 6 + z],
src->surfaces[m * 6 + z], NULL, NULL);
fit_rect_format_inclusive(dst->base.base.info.format,
&rect,
dst->surfaces[l * 6 + z]->desc.Width,
dst->surfaces[l * 6 + z]->desc.Height);
NineSurface9_CopyMemToDefault(dst->surfaces[l * 6 + z],
src->surfaces[m * 6 + z],
(POINT *)&rect,
&rect);
rect_minify_inclusive(&rect);
}
u_box_origin_2d(0, 0, &src->dirty_rect[z]);
m -= l;
}
} else
@@ -1352,9 +1380,12 @@ NineDevice9_UpdateTexture( struct NineDevice9 *This,
struct NineVolumeTexture9 *dst = NineVolumeTexture9(dstb);
struct NineVolumeTexture9 *src = NineVolumeTexture9(srcb);

if (src->dirty_box.width == 0)
return D3D_OK;
for (l = 0; l <= last_level; ++l, ++m)
NineVolume9_CopyMemToDefault(dst->volumes[l],
src->volumes[m], 0, 0, 0, NULL);
u_box_3d(0, 0, 0, 0, 0, 0, &src->dirty_box);
} else{
assert(!"invalid texture type");
}

+ 44
- 0
src/gallium/state_trackers/nine/nine_pipe.h View File

@@ -27,6 +27,7 @@
#include "pipe/p_format.h"
#include "pipe/p_screen.h"
#include "pipe/p_state.h" /* pipe_box */
#include "util/macros.h"
#include "util/u_rect.h"
#include "util/u_format.h"
#include "nine_helpers.h"
@@ -81,6 +82,49 @@ rect_to_pipe_box(struct pipe_box *dst, const RECT *src)
dst->depth = 1;
}

static inline void
pipe_box_to_rect(RECT *dst, const struct pipe_box *src)
{
dst->left = src->x;
dst->right = src->x + src->width;
dst->top = src->y;
dst->bottom = src->y + src->height;
}

static inline void
rect_minify_inclusive(RECT *rect)
{
rect->left = rect->left >> 2;
rect->top = rect->top >> 2;
rect->right = DIV_ROUND_UP(rect->right, 2);
rect->bottom = DIV_ROUND_UP(rect->bottom, 2);
}

/* We suppose:
* 0 <= rect->left < rect->right
* 0 <= rect->top < rect->bottom
*/
static inline void
fit_rect_format_inclusive(enum pipe_format format, RECT *rect, int width, int height)
{
const unsigned w = util_format_get_blockwidth(format);
const unsigned h = util_format_get_blockheight(format);

if (util_format_is_compressed(format)) {
rect->left = rect->left - rect->left % w;
rect->top = rect->top - rect->top % h;
rect->right = (rect->right % w) == 0 ?
rect->right :
rect->right - (rect->right % w) + w;
rect->bottom = (rect->bottom % h) == 0 ?
rect->bottom :
rect->bottom - (rect->bottom % h) + h;
}

rect->right = MIN2(rect->right, width);
rect->bottom = MIN2(rect->bottom, height);
}

static inline boolean
rect_to_pipe_box_clamp(struct pipe_box *dst, const RECT *src)
{

Loading…
Cancel
Save