summaryrefslogtreecommitdiffstats
path: root/src/gallium/state_trackers/nine/surface9.c
diff options
context:
space:
mode:
authorJoakim Sindholt <[email protected]>2011-08-04 15:14:06 +0200
committerEmil Velikov <[email protected]>2014-11-18 02:02:54 +0000
commitfdd96578ef2dfe9c4ad5aab5858036298d444a64 (patch)
tree3230b0fb321381250a506503825318facb10ca73 /src/gallium/state_trackers/nine/surface9.c
parent7d2573b5376bb4f9ce9a50e0b965e06032b135a9 (diff)
nine: Add state tracker nine for Direct3D9 (v3)
Work of Joakim Sindholt (zhasha) and Christoph Bumiller (chrisbmr). DRI3 port done by Axel Davy (mannerov). v2: - nine_debug.c: klass extended from 32 chars to 96 (for sure) by glennk - Nine improvements by Axel Davy (which also fixed some wine tests) - by Emil Velikov: - convert to static/shared drivers - Sort and cleanup the includes - Use AM_CPPFLAGS for the defines - Add the linker garbage collector - Restrict the exported symbols (think llvm) v3: - small nine fixes - build system improvements by Emil Velikov v4: [Emil Velikov] - Do no link against libudev. No longer needed. Acked-by: Jose Fonseca <[email protected]> Reviewed-by: Marek Olšák <[email protected]> Reviewed-by: Axel Davy <[email protected]> Signed-off-by: David Heidelberg <[email protected]>
Diffstat (limited to 'src/gallium/state_trackers/nine/surface9.c')
-rw-r--r--src/gallium/state_trackers/nine/surface9.c711
1 files changed, 711 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/nine/surface9.c b/src/gallium/state_trackers/nine/surface9.c
new file mode 100644
index 00000000000..42a9e05dabd
--- /dev/null
+++ b/src/gallium/state_trackers/nine/surface9.c
@@ -0,0 +1,711 @@
+/*
+ * Copyright 2011 Joakim Sindholt <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "surface9.h"
+#include "device9.h"
+#include "basetexture9.h" /* for marking dirty */
+
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+#include "nine_dump.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_state.h"
+
+#include "util/u_math.h"
+#include "util/u_inlines.h"
+#include "util/u_surface.h"
+
+#define DBG_CHANNEL DBG_SURFACE
+
+HRESULT
+NineSurface9_ctor( struct NineSurface9 *This,
+ struct NineUnknownParams *pParams,
+ struct NineUnknown *pContainer,
+ struct pipe_resource *pResource,
+ uint8_t TextureType,
+ unsigned Level,
+ unsigned Layer,
+ D3DSURFACE_DESC *pDesc )
+{
+ HRESULT hr;
+
+ DBG("This=%p pDevice=%p pResource=%p Level=%u Layer=%u pDesc=%p\n",
+ This, pParams->device, pResource, Level, Layer, pDesc);
+
+ /* Mark this as a special surface held by another internal resource. */
+ pParams->container = pContainer;
+
+ user_assert(!(pDesc->Usage & D3DUSAGE_DYNAMIC) ||
+ (pDesc->Pool != D3DPOOL_MANAGED), D3DERR_INVALIDCALL);
+
+ assert(pResource ||
+ pDesc->Pool != D3DPOOL_DEFAULT || pDesc->Format == D3DFMT_NULL);
+
+ This->base.info.screen = pParams->device->screen;
+ This->base.info.target = PIPE_TEXTURE_2D;
+ This->base.info.format = d3d9_to_pipe_format(pDesc->Format);
+ This->base.info.width0 = pDesc->Width;
+ This->base.info.height0 = pDesc->Height;
+ This->base.info.depth0 = 1;
+ This->base.info.last_level = 0;
+ This->base.info.array_size = 1;
+ This->base.info.nr_samples = pDesc->MultiSampleType;
+ This->base.info.usage = PIPE_USAGE_DEFAULT;
+ This->base.info.bind = PIPE_BIND_SAMPLER_VIEW;
+ This->base.info.flags = 0;
+
+ if (pDesc->Usage & D3DUSAGE_RENDERTARGET)
+ This->base.info.bind |= PIPE_BIND_RENDER_TARGET;
+ if (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL)
+ This->base.info.bind |= PIPE_BIND_DEPTH_STENCIL;
+
+ if (pDesc->Pool == D3DPOOL_SYSTEMMEM) {
+ This->base.info.usage = PIPE_USAGE_STAGING;
+ if (pResource)
+ This->base.data = (uint8_t *)pResource; /* this is *pSharedHandle */
+ pResource = NULL;
+ } else {
+ if (pResource && (pDesc->Usage & D3DUSAGE_DYNAMIC))
+ pResource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
+ pipe_resource_reference(&This->base.resource, pResource);
+ }
+
+ hr = NineResource9_ctor(&This->base, pParams, FALSE, D3DRTYPE_SURFACE,
+ pDesc->Pool);
+ if (FAILED(hr))
+ return hr;
+ This->base.usage = pDesc->Usage;
+
+ This->pipe = This->base.base.device->pipe;
+ This->transfer = NULL;
+
+ This->texture = TextureType;
+ This->level = Level;
+ This->level_actual = Level;
+ This->layer = Layer;
+ This->desc = *pDesc;
+
+ This->stride = util_format_get_stride(This->base.info.format, pDesc->Width);
+ This->stride = align(This->stride, 4);
+
+ if (!pResource && !This->base.data) {
+ hr = NineSurface9_AllocateData(This);
+ if (FAILED(hr))
+ return hr;
+ } else {
+ if (pResource && NineSurface9_IsOffscreenPlain(This))
+ pResource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
+ }
+
+ NineSurface9_Dump(This);
+
+ return D3D_OK;
+}
+
+void
+NineSurface9_dtor( struct NineSurface9 *This )
+{
+ if (This->transfer)
+ NineSurface9_UnlockRect(This);
+ NineSurface9_ClearDirtyRects(This);
+
+ pipe_surface_reference(&This->surface[0], NULL);
+ pipe_surface_reference(&This->surface[1], NULL);
+
+ NineResource9_dtor(&This->base);
+}
+
+struct pipe_surface *
+NineSurface9_CreatePipeSurface( struct NineSurface9 *This, const int sRGB )
+{
+ struct pipe_context *pipe = This->pipe;
+ struct pipe_resource *resource = This->base.resource;
+ struct pipe_surface templ;
+
+ assert(This->desc.Pool == D3DPOOL_DEFAULT ||
+ This->desc.Pool == D3DPOOL_MANAGED);
+ assert(resource);
+
+ templ.format = sRGB ? util_format_srgb(resource->format) : resource->format;
+ templ.u.tex.level = This->level;
+ templ.u.tex.first_layer = This->layer;
+ templ.u.tex.last_layer = This->layer;
+
+ This->surface[sRGB] = pipe->create_surface(pipe, resource, &templ);
+ assert(This->surface[sRGB]);
+ return This->surface[sRGB];
+}
+
+#ifdef DEBUG
+void
+NineSurface9_Dump( struct NineSurface9 *This )
+{
+ struct NineBaseTexture9 *tex;
+ GUID id = IID_IDirect3DBaseTexture9;
+ REFIID ref = &id;
+
+ DBG("\nNineSurface9(%p->%p/%p): Pool=%s Type=%s Usage=%s\n"
+ "Dims=%ux%u Format=%s Stride=%u Lockable=%i\n"
+ "Level=%u(%u), Layer=%u\n", This, This->base.resource, This->base.data,
+ nine_D3DPOOL_to_str(This->desc.Pool),
+ nine_D3DRTYPE_to_str(This->desc.Type),
+ nine_D3DUSAGE_to_str(This->desc.Usage),
+ This->desc.Width, This->desc.Height,
+ d3dformat_to_string(This->desc.Format), This->stride,
+ This->base.resource &&
+ (This->base.resource->flags & NINE_RESOURCE_FLAG_LOCKABLE),
+ This->level, This->level_actual, This->layer);
+
+ if (!This->base.base.container)
+ return;
+ NineUnknown_QueryInterface(This->base.base.container, ref, (void **)&tex);
+ if (tex) {
+ NineBaseTexture9_Dump(tex);
+ NineUnknown_Release(NineUnknown(tex));
+ }
+}
+#endif /* DEBUG */
+
+HRESULT WINAPI
+NineSurface9_GetContainer( struct NineSurface9 *This,
+ REFIID riid,
+ void **ppContainer )
+{
+ HRESULT hr;
+ if (!NineUnknown(This)->container)
+ return E_NOINTERFACE;
+ hr = NineUnknown_QueryInterface(NineUnknown(This)->container, riid, ppContainer);
+ if (FAILED(hr))
+ DBG("QueryInterface FAILED!\n");
+ return hr;
+}
+
+static INLINE void
+NineSurface9_MarkContainerDirty( struct NineSurface9 *This )
+{
+ if (This->texture) {
+ struct NineBaseTexture9 *tex =
+ NineBaseTexture9(This->base.base.container);
+ assert(tex);
+ assert(This->texture == D3DRTYPE_TEXTURE ||
+ This->texture == D3DRTYPE_CUBETEXTURE);
+ if (This->base.pool == D3DPOOL_MANAGED)
+ tex->dirty = TRUE;
+ else
+ if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
+ tex->dirty_mip = TRUE;
+
+ BASETEX_REGISTER_UPDATE(tex);
+ }
+}
+
+HRESULT WINAPI
+NineSurface9_GetDesc( struct NineSurface9 *This,
+ D3DSURFACE_DESC *pDesc )
+{
+ user_assert(pDesc != NULL, E_POINTER);
+ *pDesc = This->desc;
+ return D3D_OK;
+}
+
+/* Wine just keeps a single directy rect and expands it to cover all
+ * the dirty rects ever added.
+ * We'll keep 2, and expand the one that fits better, just for fun.
+ */
+INLINE void
+NineSurface9_AddDirtyRect( struct NineSurface9 *This,
+ const struct pipe_box *box )
+{
+ float area[2];
+ struct u_rect rect, cover_a, cover_b;
+
+ if (!box) {
+ This->dirty_rects[0].x0 = 0;
+ This->dirty_rects[0].y0 = 0;
+ This->dirty_rects[0].x1 = This->desc.Width;
+ This->dirty_rects[0].y1 = This->desc.Height;
+
+ memset(&This->dirty_rects[1], 0, sizeof(This->dirty_rects[1]));
+ return;
+ }
+ rect.x0 = box->x;
+ rect.y0 = box->y;
+ rect.x1 = box->x + box->width;
+ rect.y1 = box->y + box->height;
+
+ if (This->dirty_rects[0].x1 == 0) {
+ This->dirty_rects[0] = rect;
+ return;
+ }
+
+ u_rect_union(&cover_a, &This->dirty_rects[0], &rect);
+ area[0] = u_rect_area(&cover_a);
+
+ if (This->dirty_rects[1].x1 == 0) {
+ area[1] = u_rect_area(&This->dirty_rects[0]);
+ if (area[0] > (area[1] * 1.25f))
+ This->dirty_rects[1] = rect;
+ else
+ This->dirty_rects[0] = cover_a;
+ } else {
+ u_rect_union(&cover_b, &This->dirty_rects[1], &rect);
+ area[1] = u_rect_area(&cover_b);
+
+ if (area[0] > area[1])
+ This->dirty_rects[1] = cover_b;
+ else
+ This->dirty_rects[0] = cover_a;
+ }
+}
+
+static INLINE uint8_t *
+NineSurface9_GetSystemMemPointer(struct NineSurface9 *This, int x, int y)
+{
+ unsigned x_offset = util_format_get_stride(This->base.info.format, x);
+
+ y = util_format_get_nblocksy(This->base.info.format, y);
+
+ assert(This->base.data);
+ return This->base.data + (y * This->stride + x_offset);
+}
+
+HRESULT WINAPI
+NineSurface9_LockRect( struct NineSurface9 *This,
+ D3DLOCKED_RECT *pLockedRect,
+ const RECT *pRect,
+ DWORD Flags )
+{
+ struct pipe_resource *resource = This->base.resource;
+ struct pipe_box box;
+ unsigned usage;
+
+ DBG("This=%p pLockedRect=%p pRect=%p[%u..%u,%u..%u] Flags=%s\n", This,
+ pLockedRect, pRect,
+ pRect ? pRect->left : 0, pRect ? pRect->right : 0,
+ pRect ? pRect->top : 0, pRect ? pRect->bottom : 0,
+ nine_D3DLOCK_to_str(Flags));
+ NineSurface9_Dump(This);
+
+#ifdef NINE_STRICT
+ user_assert(This->base.pool != D3DPOOL_DEFAULT ||
+ (resource && (resource->flags & NINE_RESOURCE_FLAG_LOCKABLE)),
+ D3DERR_INVALIDCALL);
+#endif
+ user_assert(!(Flags & ~(D3DLOCK_DISCARD |
+ D3DLOCK_DONOTWAIT |
+ D3DLOCK_NO_DIRTY_UPDATE |
+ D3DLOCK_NOOVERWRITE |
+ D3DLOCK_NOSYSLOCK | /* ignored */
+ D3DLOCK_READONLY)), D3DERR_INVALIDCALL);
+ user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)),
+ D3DERR_INVALIDCALL);
+
+ /* check if it's already locked */
+ user_assert(This->lock_count == 0, D3DERR_INVALIDCALL);
+ user_assert(pLockedRect, E_POINTER);
+
+ user_assert(This->desc.MultiSampleType == D3DMULTISAMPLE_NONE,
+ D3DERR_INVALIDCALL);
+
+ if (pRect && This->base.pool == D3DPOOL_DEFAULT &&
+ util_format_is_compressed(This->base.info.format)) {
+ const unsigned w = util_format_get_blockwidth(This->base.info.format);
+ const unsigned h = util_format_get_blockheight(This->base.info.format);
+ user_assert(!(pRect->left % w) && !(pRect->right % w) &&
+ !(pRect->top % h) && !(pRect->bottom % h),
+ D3DERR_INVALIDCALL);
+ }
+
+ if (Flags & D3DLOCK_DISCARD) {
+ usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE;
+ } else {
+ usage = (Flags & D3DLOCK_READONLY) ?
+ PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE;
+ }
+ if (Flags & D3DLOCK_DONOTWAIT)
+ usage |= PIPE_TRANSFER_DONTBLOCK;
+
+ if (pRect) {
+ rect_to_pipe_box(&box, pRect);
+ if (u_box_clip_2d(&box, &box, This->desc.Width,
+ This->desc.Height) < 0) {
+ DBG("pRect clipped by Width=%u Height=%u\n",
+ This->desc.Width, This->desc.Height);
+ return D3DERR_INVALIDCALL;
+ }
+ } else {
+ u_box_origin_2d(This->desc.Width, This->desc.Height, &box);
+ }
+
+ user_warn(This->desc.Format == D3DFMT_NULL);
+
+ if (This->base.data) {
+ DBG("returning system memory\n");
+
+ pLockedRect->Pitch = This->stride;
+ pLockedRect->pBits = NineSurface9_GetSystemMemPointer(This,
+ box.x, box.y);
+ } else {
+ DBG("mapping pipe_resource %p (level=%u usage=%x)\n",
+ resource, This->level, usage);
+
+ pLockedRect->pBits = This->pipe->transfer_map(This->pipe, resource,
+ This->level, usage, &box,
+ &This->transfer);
+ if (!This->transfer) {
+ DBG("transfer_map failed\n");
+ if (Flags & D3DLOCK_DONOTWAIT)
+ return D3DERR_WASSTILLDRAWING;
+ return D3DERR_INVALIDCALL;
+ }
+ pLockedRect->Pitch = This->transfer->stride;
+ }
+
+ if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) {
+ NineSurface9_MarkContainerDirty(This);
+ if (This->base.pool == D3DPOOL_MANAGED)
+ NineSurface9_AddDirtyRect(This, &box);
+ }
+
+ ++This->lock_count;
+ return D3D_OK;
+}
+
+HRESULT WINAPI
+NineSurface9_UnlockRect( struct NineSurface9 *This )
+{
+ DBG("This=%p lock_count=%u\n", This, This->lock_count);
+ user_assert(This->lock_count, D3DERR_INVALIDCALL);
+ if (This->transfer) {
+ This->pipe->transfer_unmap(This->pipe, This->transfer);
+ This->transfer = NULL;
+ }
+ --This->lock_count;
+ return D3D_OK;
+}
+
+HRESULT WINAPI
+NineSurface9_GetDC( struct NineSurface9 *This,
+ HDC *phdc )
+{
+ STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineSurface9_ReleaseDC( struct NineSurface9 *This,
+ HDC hdc )
+{
+ STUB(D3DERR_INVALIDCALL);
+}
+
+/* nine private */
+
+HRESULT
+NineSurface9_AllocateData( struct NineSurface9 *This )
+{
+#if 0
+ struct pipe_screen *screen = This->base.info.screen;
+ /* XXX: Can't use staging resource because apparently apps expect
+ * memory offsets to be the same across locks.
+ * NV50 doesn't support direct mapping yet so only enable this if
+ * everything else works.
+ */
+ if (This->base.pool == D3DPOOL_SYSTEMMEM) {
+ /* Allocate a staging resource to save a copy:
+ * user -> staging resource
+ * staging resource -> (blit) -> video memory
+ *
+ * Instead of:
+ * user -> system memory
+ * system memory -> transfer staging area
+ * transfer -> video memory
+ *
+ * Does this work if we "lose" the device ?
+ */
+ struct pipe_resource *resource;
+ struct pipe_resource templ;
+
+ templ.target = PIPE_TEXTURE_2D;
+ templ.format = This->base.info.format;
+ templ.width0 = This->desc.Width;
+ templ.height0 = This->desc.Height;
+ templ.depth0 = 1;
+ templ.array_size = 1;
+ templ.last_level = 0;
+ templ.nr_samples = 0;
+ templ.usage = PIPE_USAGE_STAGING;
+ templ.bind =
+ PIPE_BIND_SAMPLER_VIEW |
+ PIPE_BIND_TRANSFER_WRITE |
+ PIPE_BIND_TRANSFER_READ;
+ templ.flags = 0;
+
+ DBG("(%p(This=%p),level=%u) Allocating staging resource.\n",
+ This->base.base.container, This, This->level);
+
+ resource = screen->resource_create(screen, &templ);
+ if (!resource)
+ DBG("Failed to allocate staging resource.\n");
+
+ /* Also deallocate old staging resource. */
+ pipe_resource_reference(&This->base.resource, resource);
+ }
+#endif
+ if (!This->base.resource) {
+ const unsigned size = This->stride *
+ util_format_get_nblocksy(This->base.info.format, This->desc.Height);
+
+ DBG("(%p(This=%p),level=%u) Allocating 0x%x bytes of system memory.\n",
+ This->base.base.container, This, This->level, size);
+
+ This->base.data = (uint8_t *)MALLOC(size);
+ if (!This->base.data)
+ return E_OUTOFMEMORY;
+ }
+ return D3D_OK;
+}
+
+IDirect3DSurface9Vtbl NineSurface9_vtable = {
+ (void *)NineUnknown_QueryInterface,
+ (void *)NineUnknown_AddRef,
+ (void *)NineUnknown_Release,
+ (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+ (void *)NineResource9_SetPrivateData,
+ (void *)NineResource9_GetPrivateData,
+ (void *)NineResource9_FreePrivateData,
+ (void *)NineResource9_SetPriority,
+ (void *)NineResource9_GetPriority,
+ (void *)NineResource9_PreLoad,
+ (void *)NineResource9_GetType,
+ (void *)NineSurface9_GetContainer,
+ (void *)NineSurface9_GetDesc,
+ (void *)NineSurface9_LockRect,
+ (void *)NineSurface9_UnlockRect,
+ (void *)NineSurface9_GetDC,
+ (void *)NineSurface9_ReleaseDC
+};
+
+
+static INLINE boolean
+NineSurface9_IsDirty(struct NineSurface9 *This)
+{
+ return This->dirty_rects[0].x1 != 0;
+}
+
+HRESULT
+NineSurface9_CopySurface( struct NineSurface9 *This,
+ struct NineSurface9 *From,
+ const POINT *pDestPoint,
+ const RECT *pSourceRect )
+{
+ struct pipe_context *pipe = This->pipe;
+ struct pipe_resource *r_dst = This->base.resource;
+ struct pipe_resource *r_src = From->base.resource;
+ struct pipe_transfer *transfer;
+ struct pipe_box src_box;
+ struct pipe_box dst_box;
+ uint8_t *p_dst;
+ const uint8_t *p_src;
+
+ user_assert(This->desc.Format == From->desc.Format, D3DERR_INVALIDCALL);
+
+ dst_box.x = pDestPoint ? pDestPoint->x : 0;
+ dst_box.y = pDestPoint ? pDestPoint->y : 0;
+
+ user_assert(dst_box.x >= 0 &&
+ dst_box.y >= 0, D3DERR_INVALIDCALL);
+
+ dst_box.z = This->layer;
+ src_box.z = From->layer;
+
+ dst_box.depth = 1;
+ src_box.depth = 1;
+
+ if (pSourceRect) {
+ /* make sure it doesn't range outside the source surface */
+ user_assert(pSourceRect->left >= 0 &&
+ pSourceRect->right <= From->desc.Width &&
+ pSourceRect->top >= 0 &&
+ pSourceRect->bottom <= From->desc.Height,
+ D3DERR_INVALIDCALL);
+ if (rect_to_pipe_box_xy_only_clamp(&src_box, pSourceRect))
+ return D3D_OK;
+ } else {
+ src_box.x = 0;
+ src_box.y = 0;
+ src_box.width = From->desc.Width;
+ src_box.height = From->desc.Height;
+ }
+
+ /* limits */
+ dst_box.width = This->desc.Width - dst_box.x;
+ dst_box.height = This->desc.Height - dst_box.y;
+
+ user_assert(src_box.width <= dst_box.width &&
+ src_box.height <= dst_box.height, D3DERR_INVALIDCALL);
+
+ dst_box.width = src_box.width;
+ dst_box.height = src_box.height;
+
+ /* Don't copy to device memory of managed resources.
+ * We don't want to download it back again later.
+ */
+ if (This->base.pool == D3DPOOL_MANAGED)
+ r_dst = NULL;
+
+ /* Don't copy from stale device memory of managed resources.
+ * Also, don't copy between system and device if we don't have to.
+ */
+ if (From->base.pool == D3DPOOL_MANAGED) {
+ if (!r_dst || NineSurface9_IsDirty(From))
+ r_src = NULL;
+ }
+
+ if (r_dst && r_src) {
+ pipe->resource_copy_region(pipe,
+ r_dst, This->level,
+ dst_box.x, dst_box.y, dst_box.z,
+ r_src, From->level,
+ &src_box);
+ } else
+ if (r_dst) {
+ p_src = NineSurface9_GetSystemMemPointer(From, src_box.x, src_box.y);
+
+ pipe->transfer_inline_write(pipe, r_dst, This->level,
+ 0, /* WRITE|DISCARD are implicit */
+ &dst_box, p_src, From->stride, 0);
+ } else
+ if (r_src) {
+ p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0);
+
+ p_src = pipe->transfer_map(pipe, r_src, From->level,
+ PIPE_TRANSFER_READ,
+ &src_box, &transfer);
+ if (!p_src)
+ return D3DERR_DRIVERINTERNALERROR;
+
+ util_copy_rect(p_dst, This->base.info.format,
+ This->stride, dst_box.x, dst_box.y,
+ dst_box.width, dst_box.height,
+ p_src,
+ transfer->stride, src_box.x, src_box.y);
+
+ pipe->transfer_unmap(pipe, transfer);
+ } else {
+ p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0);
+ p_src = NineSurface9_GetSystemMemPointer(From, 0, 0);
+
+ util_copy_rect(p_dst, This->base.info.format,
+ This->stride, dst_box.x, dst_box.y,
+ dst_box.width, dst_box.height,
+ p_src,
+ From->stride, src_box.x, src_box.y);
+ }
+
+ if (This->base.pool == D3DPOOL_DEFAULT ||
+ This->base.pool == D3DPOOL_MANAGED)
+ NineSurface9_MarkContainerDirty(This);
+ if (!r_dst && This->base.resource)
+ NineSurface9_AddDirtyRect(This, &dst_box);
+
+ return D3D_OK;
+}
+
+/* Gladly, rendering to a MANAGED surface is not permitted, so we will
+ * never have to do the reverse, i.e. download the surface.
+ */
+HRESULT
+NineSurface9_UploadSelf( struct NineSurface9 *This )
+{
+ struct pipe_context *pipe = This->pipe;
+ struct pipe_resource *res = This->base.resource;
+ uint8_t *ptr;
+ unsigned i;
+
+ assert(This->base.pool == D3DPOOL_MANAGED);
+
+ if (!NineSurface9_IsDirty(This))
+ return D3D_OK;
+
+ for (i = 0; i < Elements(This->dirty_rects); ++i) {
+ struct pipe_box box;
+ nine_u_rect_to_pipe_box(&box, &This->dirty_rects[i], This->layer);
+
+ if (box.width == 0)
+ break;
+ ptr = NineSurface9_GetSystemMemPointer(This, box.x, box.y);
+
+ pipe->transfer_inline_write(pipe, res, This->level,
+ 0,
+ &box, ptr, This->stride, 0);
+ }
+ NineSurface9_ClearDirtyRects(This);
+
+ return D3D_OK;
+}
+
+void
+NineSurface9_SetResourceResize( struct NineSurface9 *This,
+ struct pipe_resource *resource )
+{
+ assert(This->level == 0 && This->level_actual == 0);
+ assert(!This->lock_count);
+ assert(This->desc.Pool == D3DPOOL_DEFAULT);
+ assert(!This->texture);
+
+ pipe_resource_reference(&This->base.resource, resource);
+
+ This->desc.Width = This->base.info.width0 = resource->width0;
+ This->desc.Height = This->base.info.height0 = resource->height0;
+
+ This->stride = util_format_get_stride(This->base.info.format,
+ This->desc.Width);
+ This->stride = align(This->stride, 4);
+
+ pipe_surface_reference(&This->surface[0], NULL);
+ pipe_surface_reference(&This->surface[1], NULL);
+}
+
+
+static const GUID *NineSurface9_IIDs[] = {
+ &IID_IDirect3DSurface9,
+ &IID_IDirect3DResource9,
+ &IID_IUnknown,
+ NULL
+};
+
+HRESULT
+NineSurface9_new( struct NineDevice9 *pDevice,
+ struct NineUnknown *pContainer,
+ struct pipe_resource *pResource,
+ uint8_t TextureType,
+ unsigned Level,
+ unsigned Layer,
+ D3DSURFACE_DESC *pDesc,
+ struct NineSurface9 **ppOut )
+{
+ NINE_DEVICE_CHILD_NEW(Surface9, ppOut, pDevice, /* args */
+ pContainer, pResource,
+ TextureType, Level, Layer, pDesc);
+}