OSDN Git Service

st/nine: Fix locking CubeTexture surfaces.
[android-x86/external-mesa.git] / src / gallium / state_trackers / nine / surface9.c
1 /*
2  * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21  * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23 #include "surface9.h"
24 #include "device9.h"
25
26 /* for marking dirty */
27 #include "basetexture9.h"
28 #include "texture9.h"
29 #include "cubetexture9.h"
30
31 #include "nine_helpers.h"
32 #include "nine_pipe.h"
33 #include "nine_dump.h"
34
35 #include "pipe/p_context.h"
36 #include "pipe/p_screen.h"
37 #include "pipe/p_state.h"
38
39 #include "util/u_math.h"
40 #include "util/u_inlines.h"
41 #include "util/u_surface.h"
42
43 #define DBG_CHANNEL DBG_SURFACE
44
45 HRESULT
46 NineSurface9_ctor( struct NineSurface9 *This,
47                    struct NineUnknownParams *pParams,
48                    struct NineUnknown *pContainer,
49                    struct pipe_resource *pResource,
50                    void *user_buffer,
51                    uint8_t TextureType,
52                    unsigned Level,
53                    unsigned Layer,
54                    D3DSURFACE_DESC *pDesc )
55 {
56     HRESULT hr;
57     union pipe_color_union rgba = {0};
58     struct pipe_surface *surf;
59     struct pipe_context *pipe = pParams->device->pipe;
60     bool allocate = !pContainer && pDesc->Format != D3DFMT_NULL;
61     D3DMULTISAMPLE_TYPE multisample_type;
62
63     DBG("This=%p pDevice=%p pResource=%p Level=%u Layer=%u pDesc=%p\n",
64         This, pParams->device, pResource, Level, Layer, pDesc);
65
66     /* Mark this as a special surface held by another internal resource. */
67     pParams->container = pContainer;
68     /* Make sure there's a Desc */
69     assert(pDesc);
70
71     /* D3DUSAGE_DYNAMIC isn't allowed on managed buffers */
72     user_assert(!(pDesc->Usage & D3DUSAGE_DYNAMIC) ||
73                 (pDesc->Pool != D3DPOOL_MANAGED), D3DERR_INVALIDCALL);
74
75     assert(allocate || pResource || user_buffer ||
76            pDesc->Format == D3DFMT_NULL);
77     assert(!allocate || (!pResource && !user_buffer));
78     assert(!pResource || !user_buffer);
79     assert(!user_buffer || pDesc->Pool != D3DPOOL_DEFAULT);
80     assert(!pResource || pDesc->Pool == D3DPOOL_DEFAULT);
81     /* Allocation only from create_zs_or_rt_surface with params 0 0 0 */
82     assert(!allocate || (Level == 0 && Layer == 0 && TextureType == 0));
83
84     This->data = (uint8_t *)user_buffer;
85
86     multisample_type = pDesc->MultiSampleType;
87
88     /* Map MultiSampleQuality to MultiSampleType */
89     hr = d3dmultisample_type_check(pParams->device->screen,
90                                    pDesc->Format,
91                                    &multisample_type,
92                                    pDesc->MultiSampleQuality,
93                                    NULL);
94     if (FAILED(hr)) {
95         return hr;
96     }
97
98     /* TODO: this is (except width and height) duplicate from
99      * container info (in the pContainer case). Some refactoring is
100      * needed to avoid duplication */
101     This->base.info.screen = pParams->device->screen;
102     This->base.info.target = PIPE_TEXTURE_2D;
103     This->base.info.width0 = pDesc->Width;
104     This->base.info.height0 = pDesc->Height;
105     This->base.info.depth0 = 1;
106     This->base.info.last_level = 0;
107     This->base.info.array_size = 1;
108     This->base.info.nr_samples = multisample_type;
109     This->base.info.usage = PIPE_USAGE_DEFAULT;
110     This->base.info.bind = PIPE_BIND_SAMPLER_VIEW; /* StretchRect */
111
112     if (pDesc->Usage & D3DUSAGE_RENDERTARGET) {
113         This->base.info.bind |= PIPE_BIND_RENDER_TARGET;
114     } else if (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL) {
115         This->base.info.bind = d3d9_get_pipe_depth_format_bindings(pDesc->Format);
116         if (TextureType)
117             This->base.info.bind |= PIPE_BIND_SAMPLER_VIEW;
118     }
119
120     This->base.info.flags = 0;
121     This->base.info.format = d3d9_to_pipe_format_checked(This->base.info.screen,
122                                                          pDesc->Format,
123                                                          This->base.info.target,
124                                                          This->base.info.nr_samples,
125                                                          This->base.info.bind,
126                                                          FALSE,
127                                                          pDesc->Pool == D3DPOOL_SCRATCH);
128
129     if (This->base.info.format == PIPE_FORMAT_NONE && pDesc->Format != D3DFMT_NULL)
130         return D3DERR_INVALIDCALL;
131
132     if (allocate && compressed_format(pDesc->Format)) {
133         const unsigned w = util_format_get_blockwidth(This->base.info.format);
134         const unsigned h = util_format_get_blockheight(This->base.info.format);
135
136         /* Note: In the !allocate case, the test could fail (lower levels of a texture) */
137         user_assert(!(pDesc->Width % w) && !(pDesc->Height % h), D3DERR_INVALIDCALL);
138     }
139
140     /* Get true format */
141     This->format_conversion = d3d9_to_pipe_format_checked(This->base.info.screen,
142                                                          pDesc->Format,
143                                                          This->base.info.target,
144                                                          This->base.info.nr_samples,
145                                                          This->base.info.bind,
146                                                          FALSE,
147                                                          TRUE);
148     if (This->base.info.format != This->format_conversion) {
149         This->data_conversion = align_calloc(
150             nine_format_get_level_alloc_size(This->format_conversion,
151                                              pDesc->Width,
152                                              pDesc->Height,
153                                              0), 32);
154         if (!This->data_conversion)
155             return E_OUTOFMEMORY;
156         This->stride_conversion = nine_format_get_stride(This->format_conversion,
157                                                          pDesc->Width);
158     }
159
160     if ((allocate && pDesc->Pool != D3DPOOL_DEFAULT) || pDesc->Format == D3DFMT_NULL) {
161         /* Ram buffer with no parent. Has to allocate the resource itself */
162         assert(!user_buffer);
163         This->data = align_calloc(
164             nine_format_get_level_alloc_size(This->base.info.format,
165                                              pDesc->Width,
166                                              pDesc->Height,
167                                              0), 32);
168         if (!This->data)
169             return E_OUTOFMEMORY;
170     }
171
172     hr = NineResource9_ctor(&This->base, pParams, pResource,
173                             allocate && (pDesc->Pool == D3DPOOL_DEFAULT),
174                             D3DRTYPE_SURFACE, pDesc->Pool, pDesc->Usage);
175
176     if (FAILED(hr))
177         return hr;
178
179     This->pipe = This->base.base.device->pipe;
180     This->transfer = NULL;
181
182     This->texture = TextureType;
183     This->level = Level;
184     This->level_actual = Level;
185     This->layer = Layer;
186     This->desc = *pDesc;
187
188     This->stride = nine_format_get_stride(This->base.info.format, pDesc->Width);
189
190     if (This->base.resource && (pDesc->Usage & D3DUSAGE_DYNAMIC))
191         This->base.resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
192
193     /* TODO: investigate what else exactly needs to be cleared */
194     if (This->base.resource && (pDesc->Usage & D3DUSAGE_RENDERTARGET)) {
195         surf = NineSurface9_GetSurface(This, 0);
196         pipe->clear_render_target(pipe, surf, &rgba, 0, 0, pDesc->Width, pDesc->Height, false);
197     }
198
199     NineSurface9_Dump(This);
200
201     return D3D_OK;
202 }
203
204 void
205 NineSurface9_dtor( struct NineSurface9 *This )
206 {
207     DBG("This=%p\n", This);
208
209     if (This->transfer)
210         NineSurface9_UnlockRect(This);
211
212     pipe_surface_reference(&This->surface[0], NULL);
213     pipe_surface_reference(&This->surface[1], NULL);
214
215     /* Release system memory when we have to manage it (no parent) */
216     if (!This->base.base.container && This->data)
217         align_free(This->data);
218     if (This->data_conversion)
219         align_free(This->data_conversion);
220     NineResource9_dtor(&This->base);
221 }
222
223 struct pipe_surface *
224 NineSurface9_CreatePipeSurface( struct NineSurface9 *This, const int sRGB )
225 {
226     struct pipe_context *pipe = This->pipe;
227     struct pipe_screen *screen = pipe->screen;
228     struct pipe_resource *resource = This->base.resource;
229     struct pipe_surface templ;
230     enum pipe_format srgb_format;
231
232     assert(This->desc.Pool == D3DPOOL_DEFAULT);
233     assert(resource);
234
235     srgb_format = util_format_srgb(resource->format);
236     if (sRGB && srgb_format != PIPE_FORMAT_NONE &&
237         screen->is_format_supported(screen, srgb_format,
238                                     resource->target, 0, resource->bind))
239         templ.format = srgb_format;
240     else
241         templ.format = resource->format;
242     templ.u.tex.level = This->level;
243     templ.u.tex.first_layer = This->layer;
244     templ.u.tex.last_layer = This->layer;
245
246     This->surface[sRGB] = pipe->create_surface(pipe, resource, &templ);
247     assert(This->surface[sRGB]);
248     return This->surface[sRGB];
249 }
250
251 #ifdef DEBUG
252 void
253 NineSurface9_Dump( struct NineSurface9 *This )
254 {
255     struct NineBaseTexture9 *tex;
256     GUID id = IID_IDirect3DBaseTexture9;
257     REFIID ref = &id;
258
259     DBG("\nNineSurface9(%p->%p/%p): Pool=%s Type=%s Usage=%s\n"
260         "Dims=%ux%u Format=%s Stride=%u Lockable=%i\n"
261         "Level=%u(%u), Layer=%u\n", This, This->base.resource, This->data,
262         nine_D3DPOOL_to_str(This->desc.Pool),
263         nine_D3DRTYPE_to_str(This->desc.Type),
264         nine_D3DUSAGE_to_str(This->desc.Usage),
265         This->desc.Width, This->desc.Height,
266         d3dformat_to_string(This->desc.Format), This->stride,
267         This->base.resource &&
268         (This->base.resource->flags & NINE_RESOURCE_FLAG_LOCKABLE),
269         This->level, This->level_actual, This->layer);
270
271     if (!This->base.base.container)
272         return;
273     NineUnknown_QueryInterface(This->base.base.container, ref, (void **)&tex);
274     if (tex) {
275         NineBaseTexture9_Dump(tex);
276         NineUnknown_Release(NineUnknown(tex));
277     }
278 }
279 #endif /* DEBUG */
280
281 HRESULT NINE_WINAPI
282 NineSurface9_GetContainer( struct NineSurface9 *This,
283                            REFIID riid,
284                            void **ppContainer )
285 {
286     HRESULT hr;
287     char guid_str[64];
288
289     DBG("This=%p riid=%p id=%s ppContainer=%p\n",
290         This, riid, riid ? GUID_sprintf(guid_str, riid) : "", ppContainer);
291
292     if (!ppContainer) return E_POINTER;
293
294     /* Return device for OffscreenPlainSurface, DepthStencilSurface and RenderTarget */
295     if (!NineUnknown(This)->container) {
296         *ppContainer = NineUnknown(This)->device;
297         NineUnknown_AddRef(NineUnknown(*ppContainer));
298
299         return D3D_OK;
300     }
301
302     hr = NineUnknown_QueryInterface(NineUnknown(This)->container, riid, ppContainer);
303     if (FAILED(hr))
304         DBG("QueryInterface FAILED!\n");
305     return hr;
306 }
307
308 void
309 NineSurface9_MarkContainerDirty( struct NineSurface9 *This )
310 {
311     if (This->texture) {
312         struct NineBaseTexture9 *tex =
313             NineBaseTexture9(This->base.base.container);
314         assert(tex);
315         assert(This->texture == D3DRTYPE_TEXTURE ||
316                This->texture == D3DRTYPE_CUBETEXTURE);
317         if (This->base.pool == D3DPOOL_MANAGED)
318             tex->managed.dirty = TRUE;
319         else
320         if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
321             tex->dirty_mip = TRUE;
322
323         BASETEX_REGISTER_UPDATE(tex);
324     }
325 }
326
327 HRESULT NINE_WINAPI
328 NineSurface9_GetDesc( struct NineSurface9 *This,
329                       D3DSURFACE_DESC *pDesc )
330 {
331     user_assert(pDesc != NULL, E_POINTER);
332     *pDesc = This->desc;
333     return D3D_OK;
334 }
335
336 /* Add the dirty rects to the source texture */
337 inline void
338 NineSurface9_AddDirtyRect( struct NineSurface9 *This,
339                            const struct pipe_box *box )
340 {
341     RECT dirty_rect;
342
343     DBG("This=%p box=%p\n", This, box);
344
345     assert (This->base.pool != D3DPOOL_MANAGED ||
346             This->texture == D3DRTYPE_CUBETEXTURE ||
347             This->texture == D3DRTYPE_TEXTURE);
348
349     if (This->base.pool == D3DPOOL_DEFAULT)
350         return;
351
352     /* Add a dirty rect to level 0 of the parent texture */
353     dirty_rect.left = box->x << This->level_actual;
354     dirty_rect.right = dirty_rect.left + (box->width << This->level_actual);
355     dirty_rect.top = box->y << This->level_actual;
356     dirty_rect.bottom = dirty_rect.top + (box->height << This->level_actual);
357
358     if (This->texture == D3DRTYPE_TEXTURE) {
359         struct NineTexture9 *tex =
360             NineTexture9(This->base.base.container);
361
362         NineTexture9_AddDirtyRect(tex, &dirty_rect);
363     } else if (This->texture == D3DRTYPE_CUBETEXTURE) {
364         struct NineCubeTexture9 *ctex =
365             NineCubeTexture9(This->base.base.container);
366
367         NineCubeTexture9_AddDirtyRect(ctex, This->layer, &dirty_rect);
368     }
369 }
370
371 static inline uint8_t *
372 NineSurface9_GetSystemMemPointer(struct NineSurface9 *This, int x, int y)
373 {
374     unsigned x_offset = util_format_get_stride(This->base.info.format, x);
375
376     y = util_format_get_nblocksy(This->base.info.format, y);
377
378     assert(This->data);
379     return This->data + (y * This->stride + x_offset);
380 }
381
382 HRESULT NINE_WINAPI
383 NineSurface9_LockRect( struct NineSurface9 *This,
384                        D3DLOCKED_RECT *pLockedRect,
385                        const RECT *pRect,
386                        DWORD Flags )
387 {
388     struct pipe_resource *resource = This->base.resource;
389     struct pipe_box box;
390     unsigned usage;
391
392     DBG("This=%p pLockedRect=%p pRect=%p[%u..%u,%u..%u] Flags=%s\n", This,
393         pLockedRect, pRect,
394         pRect ? pRect->left : 0, pRect ? pRect->right : 0,
395         pRect ? pRect->top : 0, pRect ? pRect->bottom : 0,
396         nine_D3DLOCK_to_str(Flags));
397     NineSurface9_Dump(This);
398
399     /* check if it's already locked */
400     user_assert(This->lock_count == 0, D3DERR_INVALIDCALL);
401
402     /* set pBits to NULL after lock_count check */
403     user_assert(pLockedRect, E_POINTER);
404     pLockedRect->pBits = NULL;
405
406 #ifdef NINE_STRICT
407     user_assert(This->base.pool != D3DPOOL_DEFAULT ||
408                 (resource && (resource->flags & NINE_RESOURCE_FLAG_LOCKABLE)),
409                 D3DERR_INVALIDCALL);
410 #endif
411     user_assert(!(Flags & ~(D3DLOCK_DISCARD |
412                             D3DLOCK_DONOTWAIT |
413                             D3DLOCK_NO_DIRTY_UPDATE |
414                             D3DLOCK_NOOVERWRITE |
415                             D3DLOCK_NOSYSLOCK | /* ignored */
416                             D3DLOCK_READONLY)), D3DERR_INVALIDCALL);
417     user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)),
418                 D3DERR_INVALIDCALL);
419
420     user_assert(This->desc.MultiSampleType == D3DMULTISAMPLE_NONE,
421                 D3DERR_INVALIDCALL);
422
423     if (pRect && This->desc.Pool == D3DPOOL_DEFAULT &&
424         util_format_is_compressed(This->base.info.format)) {
425         const unsigned w = util_format_get_blockwidth(This->base.info.format);
426         const unsigned h = util_format_get_blockheight(This->base.info.format);
427         user_assert((pRect->left == 0 && pRect->right == This->desc.Width &&
428                      pRect->top == 0 && pRect->bottom == This->desc.Height) ||
429                     (!(pRect->left % w) && !(pRect->right % w) &&
430                     !(pRect->top % h) && !(pRect->bottom % h)),
431                     D3DERR_INVALIDCALL);
432     }
433
434     if (Flags & D3DLOCK_DISCARD) {
435         usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE;
436     } else {
437         usage = (Flags & D3DLOCK_READONLY) ?
438             PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE;
439     }
440     if (Flags & D3DLOCK_DONOTWAIT)
441         usage |= PIPE_TRANSFER_DONTBLOCK;
442
443     if (pRect) {
444         /* Windows XP accepts invalid locking rectangles, Windows 7 rejects
445          * them. Use Windows XP behaviour for now. */
446         rect_to_pipe_box(&box, pRect);
447     } else {
448         u_box_origin_2d(This->desc.Width, This->desc.Height, &box);
449     }
450     box.z = This->layer;
451
452     user_warn(This->desc.Format == D3DFMT_NULL);
453
454     if (This->data_conversion) {
455         /* For now we only have uncompressed formats here */
456         pLockedRect->Pitch = This->stride_conversion;
457         pLockedRect->pBits = This->data_conversion + box.y * This->stride_conversion +
458             util_format_get_stride(This->format_conversion, box.x);
459     } else if (This->data) {
460         DBG("returning system memory\n");
461         /* ATI1 and ATI2 need special handling, because of d3d9 bug.
462          * We must advertise to the application as if it is uncompressed
463          * and bpp 8, and the app has a workaround to work with the fact
464          * that it is actually compressed. */
465         if (is_ATI1_ATI2(This->base.info.format)) {
466             pLockedRect->Pitch = This->desc.Width;
467             pLockedRect->pBits = This->data + box.y * This->desc.Width + box.x;
468         } else {
469             pLockedRect->Pitch = This->stride;
470             pLockedRect->pBits = NineSurface9_GetSystemMemPointer(This,
471                                                                   box.x,
472                                                                   box.y);
473         }
474     } else {
475         DBG("mapping pipe_resource %p (level=%u usage=%x)\n",
476             resource, This->level, usage);
477
478         pLockedRect->pBits = This->pipe->transfer_map(This->pipe, resource,
479                                                       This->level, usage, &box,
480                                                       &This->transfer);
481         if (!This->transfer) {
482             DBG("transfer_map failed\n");
483             if (Flags & D3DLOCK_DONOTWAIT)
484                 return D3DERR_WASSTILLDRAWING;
485             return D3DERR_INVALIDCALL;
486         }
487         pLockedRect->Pitch = This->transfer->stride;
488     }
489
490     if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) {
491         NineSurface9_MarkContainerDirty(This);
492         NineSurface9_AddDirtyRect(This, &box);
493     }
494
495     ++This->lock_count;
496     return D3D_OK;
497 }
498
499 HRESULT NINE_WINAPI
500 NineSurface9_UnlockRect( struct NineSurface9 *This )
501 {
502     DBG("This=%p lock_count=%u\n", This, This->lock_count);
503     user_assert(This->lock_count, D3DERR_INVALIDCALL);
504     if (This->transfer) {
505         This->pipe->transfer_unmap(This->pipe, This->transfer);
506         This->transfer = NULL;
507     }
508     --This->lock_count;
509
510     if (This->data_conversion) {
511         struct pipe_transfer *transfer;
512         uint8_t *dst = This->data;
513         struct pipe_box box;
514
515         u_box_origin_2d(This->desc.Width, This->desc.Height, &box);
516
517         if (!dst) {
518             dst = This->pipe->transfer_map(This->pipe,
519                                            This->base.resource,
520                                            This->level,
521                                            PIPE_TRANSFER_WRITE |
522                                            PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE,
523                                            &box, &transfer);
524             if (!dst)
525                 return D3D_OK;
526         }
527
528         (void) util_format_translate(This->base.info.format,
529                                      dst, This->data ? This->stride : transfer->stride,
530                                      0, 0,
531                                      This->format_conversion,
532                                      This->data_conversion,
533                                      This->stride_conversion,
534                                      0, 0,
535                                      This->desc.Width, This->desc.Height);
536
537         if (!This->data)
538             pipe_transfer_unmap(This->pipe, transfer);
539     }
540     return D3D_OK;
541 }
542
543 HRESULT NINE_WINAPI
544 NineSurface9_GetDC( struct NineSurface9 *This,
545                     HDC *phdc )
546 {
547     STUB(D3DERR_INVALIDCALL);
548 }
549
550 HRESULT NINE_WINAPI
551 NineSurface9_ReleaseDC( struct NineSurface9 *This,
552                         HDC hdc )
553 {
554     STUB(D3DERR_INVALIDCALL);
555 }
556
557 IDirect3DSurface9Vtbl NineSurface9_vtable = {
558     (void *)NineUnknown_QueryInterface,
559     (void *)NineUnknown_AddRef,
560     (void *)NineUnknown_Release,
561     (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
562     (void *)NineUnknown_SetPrivateData,
563     (void *)NineUnknown_GetPrivateData,
564     (void *)NineUnknown_FreePrivateData,
565     (void *)NineResource9_SetPriority,
566     (void *)NineResource9_GetPriority,
567     (void *)NineResource9_PreLoad,
568     (void *)NineResource9_GetType,
569     (void *)NineSurface9_GetContainer,
570     (void *)NineSurface9_GetDesc,
571     (void *)NineSurface9_LockRect,
572     (void *)NineSurface9_UnlockRect,
573     (void *)NineSurface9_GetDC,
574     (void *)NineSurface9_ReleaseDC
575 };
576
577 /* When this function is called, we have already checked
578  * The copy regions fit the surfaces */
579 void
580 NineSurface9_CopyMemToDefault( struct NineSurface9 *This,
581                                struct NineSurface9 *From,
582                                const POINT *pDestPoint,
583                                const RECT *pSourceRect )
584 {
585     struct pipe_context *pipe = This->pipe;
586     struct pipe_transfer *transfer = NULL;
587     struct pipe_resource *r_dst = This->base.resource;
588     struct pipe_box dst_box;
589     uint8_t *map = NULL;
590     int src_x, src_y, dst_x, dst_y, copy_width, copy_height;
591
592     assert(This->base.pool == D3DPOOL_DEFAULT &&
593            From->base.pool == D3DPOOL_SYSTEMMEM);
594
595     if (pDestPoint) {
596         dst_x = pDestPoint->x;
597         dst_y = pDestPoint->y;
598     } else {
599         dst_x = 0;
600         dst_y = 0;
601     }
602
603     if (pSourceRect) {
604         src_x = pSourceRect->left;
605         src_y = pSourceRect->top;
606         copy_width = pSourceRect->right - pSourceRect->left;
607         copy_height = pSourceRect->bottom - pSourceRect->top;
608     } else {
609         src_x = 0;
610         src_y = 0;
611         copy_width = From->desc.Width;
612         copy_height = From->desc.Height;
613     }
614
615     u_box_2d_zslice(dst_x, dst_y, This->layer,
616                     copy_width, copy_height, &dst_box);
617
618     map = pipe->transfer_map(pipe,
619                              r_dst,
620                              This->level,
621                              PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
622                              &dst_box, &transfer);
623     if (!map)
624         return;
625
626     /* Note: if formats are the sames, it will revert
627      * to normal memcpy */
628     (void) util_format_translate(r_dst->format,
629                                  map, transfer->stride,
630                                  0, 0,
631                                  From->base.info.format,
632                                  From->data, From->stride,
633                                  src_x, src_y,
634                                  copy_width, copy_height);
635
636     pipe_transfer_unmap(pipe, transfer);
637
638     if (This->data_conversion)
639         (void) util_format_translate(This->format_conversion,
640                                      This->data_conversion,
641                                      This->stride_conversion,
642                                      dst_x, dst_y,
643                                      From->base.info.format,
644                                      From->data, From->stride,
645                                      src_x, src_y,
646                                      copy_width, copy_height);
647
648     NineSurface9_MarkContainerDirty(This);
649 }
650
651 void
652 NineSurface9_CopyDefaultToMem( struct NineSurface9 *This,
653                                struct NineSurface9 *From )
654 {
655     struct pipe_context *pipe = This->pipe;
656     struct pipe_resource *r_src = From->base.resource;
657     struct pipe_transfer *transfer;
658     struct pipe_box src_box;
659     uint8_t *p_dst;
660     const uint8_t *p_src;
661
662     assert(This->base.pool == D3DPOOL_SYSTEMMEM &&
663            From->base.pool == D3DPOOL_DEFAULT);
664
665     assert(This->desc.Width == From->desc.Width);
666     assert(This->desc.Height == From->desc.Height);
667
668     u_box_origin_2d(This->desc.Width, This->desc.Height, &src_box);
669     src_box.z = From->layer;
670
671     p_src = pipe->transfer_map(pipe, r_src, From->level,
672                                PIPE_TRANSFER_READ,
673                                &src_box, &transfer);
674     p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0);
675
676     assert (p_src && p_dst);
677
678     util_copy_rect(p_dst, This->base.info.format,
679                    This->stride, 0, 0,
680                    This->desc.Width, This->desc.Height,
681                    p_src,
682                    transfer->stride, 0, 0);
683
684     pipe->transfer_unmap(pipe, transfer);
685 }
686
687
688 /* Gladly, rendering to a MANAGED surface is not permitted, so we will
689  * never have to do the reverse, i.e. download the surface.
690  */
691 HRESULT
692 NineSurface9_UploadSelf( struct NineSurface9 *This,
693                          const struct pipe_box *damaged )
694 {
695     struct pipe_context *pipe = This->pipe;
696     struct pipe_resource *res = This->base.resource;
697     uint8_t *ptr;
698     struct pipe_box box;
699
700     DBG("This=%p damaged=%p\n", This, damaged);
701
702     assert(This->base.pool == D3DPOOL_MANAGED);
703
704     if (damaged) {
705         box = *damaged;
706         box.z = This->layer;
707         box.depth = 1;
708     } else {
709         box.x = 0;
710         box.y = 0;
711         box.z = This->layer;
712         box.width = This->desc.Width;
713         box.height = This->desc.Height;
714         box.depth = 1;
715     }
716
717     ptr = NineSurface9_GetSystemMemPointer(This, box.x, box.y);
718
719     pipe->texture_subdata(pipe, res, This->level, 0,
720                           &box, ptr, This->stride, 0);
721
722     return D3D_OK;
723 }
724
725 void
726 NineSurface9_SetResourceResize( struct NineSurface9 *This,
727                                 struct pipe_resource *resource )
728 {
729     assert(This->level == 0 && This->level_actual == 0);
730     assert(!This->lock_count);
731     assert(This->desc.Pool == D3DPOOL_DEFAULT);
732     assert(!This->texture);
733
734     pipe_resource_reference(&This->base.resource, resource);
735
736     This->desc.Width = This->base.info.width0 = resource->width0;
737     This->desc.Height = This->base.info.height0 = resource->height0;
738     This->base.info.nr_samples = resource->nr_samples;
739
740     This->stride = nine_format_get_stride(This->base.info.format,
741                                           This->desc.Width);
742
743     pipe_surface_reference(&This->surface[0], NULL);
744     pipe_surface_reference(&This->surface[1], NULL);
745 }
746
747
748 static const GUID *NineSurface9_IIDs[] = {
749     &IID_IDirect3DSurface9,
750     &IID_IDirect3DResource9,
751     &IID_IUnknown,
752     NULL
753 };
754
755 HRESULT
756 NineSurface9_new( struct NineDevice9 *pDevice,
757                   struct NineUnknown *pContainer,
758                   struct pipe_resource *pResource,
759                   void *user_buffer,
760                   uint8_t TextureType,
761                   unsigned Level,
762                   unsigned Layer,
763                   D3DSURFACE_DESC *pDesc,
764                   struct NineSurface9 **ppOut )
765 {
766     NINE_DEVICE_CHILD_NEW(Surface9, ppOut, pDevice, /* args */
767                           pContainer, pResource, user_buffer,
768                           TextureType, Level, Layer, pDesc);
769 }