st/nine: Setting D3DRS_ALPHAFUNC to 0 means D3DCMP_NEVER
[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 #include "basetexture9.h" /* for marking dirty */
26
27 #include "nine_helpers.h"
28 #include "nine_pipe.h"
29 #include "nine_dump.h"
30
31 #include "pipe/p_context.h"
32 #include "pipe/p_screen.h"
33 #include "pipe/p_state.h"
34
35 #include "util/u_math.h"
36 #include "util/u_inlines.h"
37 #include "util/u_surface.h"
38
39 #define DBG_CHANNEL DBG_SURFACE
40
41 #define is_ATI1_ATI2(format) (format == PIPE_FORMAT_RGTC1_UNORM || format == PIPE_FORMAT_RGTC2_UNORM)
42
43 HRESULT
44 NineSurface9_ctor( struct NineSurface9 *This,
45 struct NineUnknownParams *pParams,
46 struct NineUnknown *pContainer,
47 struct pipe_resource *pResource,
48 void *user_buffer,
49 uint8_t TextureType,
50 unsigned Level,
51 unsigned Layer,
52 D3DSURFACE_DESC *pDesc )
53 {
54 HRESULT hr;
55
56 DBG("This=%p pDevice=%p pResource=%p Level=%u Layer=%u pDesc=%p\n",
57 This, pParams->device, pResource, Level, Layer, pDesc);
58
59 /* Mark this as a special surface held by another internal resource. */
60 pParams->container = pContainer;
61
62 user_assert(!(pDesc->Usage & D3DUSAGE_DYNAMIC) ||
63 (pDesc->Pool != D3DPOOL_MANAGED), D3DERR_INVALIDCALL);
64
65 assert(pResource ||
66 pDesc->Pool != D3DPOOL_DEFAULT || pDesc->Format == D3DFMT_NULL);
67
68 assert(!pResource || !user_buffer);
69
70 This->base.info.screen = pParams->device->screen;
71 This->base.info.target = PIPE_TEXTURE_2D;
72 This->base.info.width0 = pDesc->Width;
73 This->base.info.height0 = pDesc->Height;
74 This->base.info.depth0 = 1;
75 This->base.info.last_level = 0;
76 This->base.info.array_size = 1;
77 This->base.info.nr_samples = pDesc->MultiSampleType;
78 This->base.info.usage = PIPE_USAGE_DEFAULT;
79 This->base.info.bind = PIPE_BIND_SAMPLER_VIEW;
80 This->base.info.flags = 0;
81 This->base.info.format = d3d9_to_pipe_format_checked(This->base.info.screen,
82 pDesc->Format,
83 This->base.info.target,
84 This->base.info.nr_samples,
85 This->base.info.bind,
86 FALSE);
87
88 if (pDesc->Usage & D3DUSAGE_RENDERTARGET)
89 This->base.info.bind |= PIPE_BIND_RENDER_TARGET;
90 if (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL)
91 This->base.info.bind |= PIPE_BIND_DEPTH_STENCIL;
92
93 if (pDesc->Pool == D3DPOOL_SYSTEMMEM) {
94 This->base.info.usage = PIPE_USAGE_STAGING;
95 This->data = (uint8_t *)user_buffer; /* this is *pSharedHandle */
96 assert(!pResource);
97 } else {
98 if (pResource && (pDesc->Usage & D3DUSAGE_DYNAMIC))
99 pResource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
100 }
101
102 hr = NineResource9_ctor(&This->base, pParams, pResource, FALSE, D3DRTYPE_SURFACE,
103 pDesc->Pool, pDesc->Usage);
104 if (FAILED(hr))
105 return hr;
106
107 This->pipe = This->base.base.device->pipe;
108 This->transfer = NULL;
109
110 This->texture = TextureType;
111 This->level = Level;
112 This->level_actual = Level;
113 This->layer = Layer;
114 This->desc = *pDesc;
115
116 This->stride = util_format_get_stride(This->base.info.format, pDesc->Width);
117 This->stride = align(This->stride, 4);
118
119 if (!pResource && !This->data) {
120 const unsigned size = This->stride *
121 util_format_get_nblocksy(This->base.info.format, This->desc.Height);
122
123 DBG("(%p(This=%p),level=%u) Allocating 0x%x bytes of system memory.\n",
124 This->base.base.container, This, This->level, size);
125
126 This->data = (uint8_t *)MALLOC(size);
127 if (!This->data)
128 return E_OUTOFMEMORY;
129 This->manage_data = TRUE;
130 } else {
131 if (pResource && NineSurface9_IsOffscreenPlain(This))
132 pResource->flags |= NINE_RESOURCE_FLAG_LOCKABLE; /* why setting this flag there ? too late ? should be before NineResource9_ctor call perhaps ? */
133 }
134
135 NineSurface9_Dump(This);
136
137 return D3D_OK;
138 }
139
140 void
141 NineSurface9_dtor( struct NineSurface9 *This )
142 {
143 if (This->transfer)
144 NineSurface9_UnlockRect(This);
145 NineSurface9_ClearDirtyRects(This);
146
147 pipe_surface_reference(&This->surface[0], NULL);
148 pipe_surface_reference(&This->surface[1], NULL);
149
150 /* release allocated system memory for non-D3DPOOL_DEFAULT resources */
151 if (This->manage_data && This->data)
152 FREE(This->data);
153 NineResource9_dtor(&This->base);
154 }
155
156 struct pipe_surface *
157 NineSurface9_CreatePipeSurface( struct NineSurface9 *This, const int sRGB )
158 {
159 struct pipe_context *pipe = This->pipe;
160 struct pipe_screen *screen = pipe->screen;
161 struct pipe_resource *resource = This->base.resource;
162 struct pipe_surface templ;
163 enum pipe_format srgb_format;
164
165 assert(This->desc.Pool == D3DPOOL_DEFAULT ||
166 This->desc.Pool == D3DPOOL_MANAGED);
167 assert(resource);
168
169 srgb_format = util_format_srgb(resource->format);
170 if (sRGB && srgb_format != PIPE_FORMAT_NONE &&
171 screen->is_format_supported(screen, srgb_format,
172 resource->target, 0, resource->bind))
173 templ.format = srgb_format;
174 else
175 templ.format = resource->format;
176 templ.u.tex.level = This->level;
177 templ.u.tex.first_layer = This->layer;
178 templ.u.tex.last_layer = This->layer;
179
180 This->surface[sRGB] = pipe->create_surface(pipe, resource, &templ);
181 assert(This->surface[sRGB]);
182 return This->surface[sRGB];
183 }
184
185 #ifdef DEBUG
186 void
187 NineSurface9_Dump( struct NineSurface9 *This )
188 {
189 struct NineBaseTexture9 *tex;
190 GUID id = IID_IDirect3DBaseTexture9;
191 REFIID ref = &id;
192
193 DBG("\nNineSurface9(%p->%p/%p): Pool=%s Type=%s Usage=%s\n"
194 "Dims=%ux%u Format=%s Stride=%u Lockable=%i\n"
195 "Level=%u(%u), Layer=%u\n", This, This->base.resource, This->data,
196 nine_D3DPOOL_to_str(This->desc.Pool),
197 nine_D3DRTYPE_to_str(This->desc.Type),
198 nine_D3DUSAGE_to_str(This->desc.Usage),
199 This->desc.Width, This->desc.Height,
200 d3dformat_to_string(This->desc.Format), This->stride,
201 This->base.resource &&
202 (This->base.resource->flags & NINE_RESOURCE_FLAG_LOCKABLE),
203 This->level, This->level_actual, This->layer);
204
205 if (!This->base.base.container)
206 return;
207 NineUnknown_QueryInterface(This->base.base.container, ref, (void **)&tex);
208 if (tex) {
209 NineBaseTexture9_Dump(tex);
210 NineUnknown_Release(NineUnknown(tex));
211 }
212 }
213 #endif /* DEBUG */
214
215 HRESULT WINAPI
216 NineSurface9_GetContainer( struct NineSurface9 *This,
217 REFIID riid,
218 void **ppContainer )
219 {
220 HRESULT hr;
221 if (!NineUnknown(This)->container)
222 return E_NOINTERFACE;
223 hr = NineUnknown_QueryInterface(NineUnknown(This)->container, riid, ppContainer);
224 if (FAILED(hr))
225 DBG("QueryInterface FAILED!\n");
226 return hr;
227 }
228
229 static INLINE void
230 NineSurface9_MarkContainerDirty( struct NineSurface9 *This )
231 {
232 if (This->texture) {
233 struct NineBaseTexture9 *tex =
234 NineBaseTexture9(This->base.base.container);
235 assert(tex);
236 assert(This->texture == D3DRTYPE_TEXTURE ||
237 This->texture == D3DRTYPE_CUBETEXTURE);
238 if (This->base.pool == D3DPOOL_MANAGED)
239 tex->dirty = TRUE;
240 else
241 if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
242 tex->dirty_mip = TRUE;
243
244 BASETEX_REGISTER_UPDATE(tex);
245 }
246 }
247
248 HRESULT WINAPI
249 NineSurface9_GetDesc( struct NineSurface9 *This,
250 D3DSURFACE_DESC *pDesc )
251 {
252 user_assert(pDesc != NULL, E_POINTER);
253 *pDesc = This->desc;
254 return D3D_OK;
255 }
256
257 /* Wine just keeps a single directy rect and expands it to cover all
258 * the dirty rects ever added.
259 * We'll keep 2, and expand the one that fits better, just for fun.
260 */
261 INLINE void
262 NineSurface9_AddDirtyRect( struct NineSurface9 *This,
263 const struct pipe_box *box )
264 {
265 float area[2];
266 struct u_rect rect, cover_a, cover_b;
267
268 DBG("This=%p box=%p\n", This, box);
269
270 if (!box) {
271 This->dirty_rects[0].x0 = 0;
272 This->dirty_rects[0].y0 = 0;
273 This->dirty_rects[0].x1 = This->desc.Width;
274 This->dirty_rects[0].y1 = This->desc.Height;
275
276 memset(&This->dirty_rects[1], 0, sizeof(This->dirty_rects[1]));
277 return;
278 }
279 rect.x0 = box->x;
280 rect.y0 = box->y;
281 rect.x1 = box->x + box->width;
282 rect.y1 = box->y + box->height;
283
284 if (This->dirty_rects[0].x1 == 0) {
285 This->dirty_rects[0] = rect;
286 return;
287 }
288
289 u_rect_union(&cover_a, &This->dirty_rects[0], &rect);
290 area[0] = u_rect_area(&cover_a);
291
292 if (This->dirty_rects[1].x1 == 0) {
293 area[1] = u_rect_area(&This->dirty_rects[0]);
294 if (area[0] > (area[1] * 1.25f))
295 This->dirty_rects[1] = rect;
296 else
297 This->dirty_rects[0] = cover_a;
298 } else {
299 u_rect_union(&cover_b, &This->dirty_rects[1], &rect);
300 area[1] = u_rect_area(&cover_b);
301
302 if (area[0] > area[1])
303 This->dirty_rects[1] = cover_b;
304 else
305 This->dirty_rects[0] = cover_a;
306 }
307 }
308
309 static INLINE uint8_t *
310 NineSurface9_GetSystemMemPointer(struct NineSurface9 *This, int x, int y)
311 {
312 unsigned x_offset = util_format_get_stride(This->base.info.format, x);
313
314 y = util_format_get_nblocksy(This->base.info.format, y);
315
316 assert(This->data);
317 return This->data + (y * This->stride + x_offset);
318 }
319
320 HRESULT WINAPI
321 NineSurface9_LockRect( struct NineSurface9 *This,
322 D3DLOCKED_RECT *pLockedRect,
323 const RECT *pRect,
324 DWORD Flags )
325 {
326 struct pipe_resource *resource = This->base.resource;
327 struct pipe_box box;
328 unsigned usage;
329
330 DBG("This=%p pLockedRect=%p pRect=%p[%u..%u,%u..%u] Flags=%s\n", This,
331 pLockedRect, pRect,
332 pRect ? pRect->left : 0, pRect ? pRect->right : 0,
333 pRect ? pRect->top : 0, pRect ? pRect->bottom : 0,
334 nine_D3DLOCK_to_str(Flags));
335 NineSurface9_Dump(This);
336
337 #ifdef NINE_STRICT
338 user_assert(This->base.pool != D3DPOOL_DEFAULT ||
339 (resource && (resource->flags & NINE_RESOURCE_FLAG_LOCKABLE)),
340 D3DERR_INVALIDCALL);
341 #endif
342 user_assert(!(Flags & ~(D3DLOCK_DISCARD |
343 D3DLOCK_DONOTWAIT |
344 D3DLOCK_NO_DIRTY_UPDATE |
345 D3DLOCK_NOOVERWRITE |
346 D3DLOCK_NOSYSLOCK | /* ignored */
347 D3DLOCK_READONLY)), D3DERR_INVALIDCALL);
348 user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)),
349 D3DERR_INVALIDCALL);
350
351 /* check if it's already locked */
352 user_assert(This->lock_count == 0, D3DERR_INVALIDCALL);
353 user_assert(pLockedRect, E_POINTER);
354
355 user_assert(This->desc.MultiSampleType == D3DMULTISAMPLE_NONE,
356 D3DERR_INVALIDCALL);
357
358 if (pRect && This->base.pool == D3DPOOL_DEFAULT &&
359 util_format_is_compressed(This->base.info.format)) {
360 const unsigned w = util_format_get_blockwidth(This->base.info.format);
361 const unsigned h = util_format_get_blockheight(This->base.info.format);
362 user_assert(!(pRect->left % w) && !(pRect->right % w) &&
363 !(pRect->top % h) && !(pRect->bottom % h),
364 D3DERR_INVALIDCALL);
365 }
366
367 if (Flags & D3DLOCK_DISCARD) {
368 usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE;
369 } else {
370 usage = (Flags & D3DLOCK_READONLY) ?
371 PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE;
372 }
373 if (Flags & D3DLOCK_DONOTWAIT)
374 usage |= PIPE_TRANSFER_DONTBLOCK;
375
376 if (pRect) {
377 rect_to_pipe_box(&box, pRect);
378 if (u_box_clip_2d(&box, &box, This->desc.Width,
379 This->desc.Height) < 0) {
380 DBG("pRect clipped by Width=%u Height=%u\n",
381 This->desc.Width, This->desc.Height);
382 return D3DERR_INVALIDCALL;
383 }
384 } else {
385 u_box_origin_2d(This->desc.Width, This->desc.Height, &box);
386 }
387
388 user_warn(This->desc.Format == D3DFMT_NULL);
389
390 if (This->data) {
391 DBG("returning system memory\n");
392 /* ATI1 and ATI2 need special handling, because of d3d9 bug.
393 * We must advertise to the application as if it is uncompressed
394 * and bpp 8, and the app has a workaround to work with the fact
395 * that it is actually compressed. */
396 if (is_ATI1_ATI2(This->base.info.format)) {
397 pLockedRect->Pitch = This->desc.Height;
398 pLockedRect->pBits = This->data + box.y * This->desc.Height + box.x;
399 } else {
400 pLockedRect->Pitch = This->stride;
401 pLockedRect->pBits = NineSurface9_GetSystemMemPointer(This,
402 box.x,
403 box.y);
404 }
405 } else {
406 DBG("mapping pipe_resource %p (level=%u usage=%x)\n",
407 resource, This->level, usage);
408
409 pLockedRect->pBits = This->pipe->transfer_map(This->pipe, resource,
410 This->level, usage, &box,
411 &This->transfer);
412 if (!This->transfer) {
413 DBG("transfer_map failed\n");
414 if (Flags & D3DLOCK_DONOTWAIT)
415 return D3DERR_WASSTILLDRAWING;
416 return D3DERR_INVALIDCALL;
417 }
418 pLockedRect->Pitch = This->transfer->stride;
419 }
420
421 if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) {
422 NineSurface9_MarkContainerDirty(This);
423 if (This->base.pool == D3DPOOL_MANAGED)
424 NineSurface9_AddDirtyRect(This, &box);
425 }
426
427 ++This->lock_count;
428 return D3D_OK;
429 }
430
431 HRESULT WINAPI
432 NineSurface9_UnlockRect( struct NineSurface9 *This )
433 {
434 DBG("This=%p lock_count=%u\n", This, This->lock_count);
435 user_assert(This->lock_count, D3DERR_INVALIDCALL);
436 if (This->transfer) {
437 This->pipe->transfer_unmap(This->pipe, This->transfer);
438 This->transfer = NULL;
439 }
440 --This->lock_count;
441 return D3D_OK;
442 }
443
444 HRESULT WINAPI
445 NineSurface9_GetDC( struct NineSurface9 *This,
446 HDC *phdc )
447 {
448 STUB(D3DERR_INVALIDCALL);
449 }
450
451 HRESULT WINAPI
452 NineSurface9_ReleaseDC( struct NineSurface9 *This,
453 HDC hdc )
454 {
455 STUB(D3DERR_INVALIDCALL);
456 }
457
458 IDirect3DSurface9Vtbl NineSurface9_vtable = {
459 (void *)NineUnknown_QueryInterface,
460 (void *)NineUnknown_AddRef,
461 (void *)NineUnknown_Release,
462 (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
463 (void *)NineResource9_SetPrivateData,
464 (void *)NineResource9_GetPrivateData,
465 (void *)NineResource9_FreePrivateData,
466 (void *)NineResource9_SetPriority,
467 (void *)NineResource9_GetPriority,
468 (void *)NineResource9_PreLoad,
469 (void *)NineResource9_GetType,
470 (void *)NineSurface9_GetContainer,
471 (void *)NineSurface9_GetDesc,
472 (void *)NineSurface9_LockRect,
473 (void *)NineSurface9_UnlockRect,
474 (void *)NineSurface9_GetDC,
475 (void *)NineSurface9_ReleaseDC
476 };
477
478
479 static INLINE boolean
480 NineSurface9_IsDirty(struct NineSurface9 *This)
481 {
482 return This->dirty_rects[0].x1 != 0;
483 }
484
485 HRESULT
486 NineSurface9_CopySurface( struct NineSurface9 *This,
487 struct NineSurface9 *From,
488 const POINT *pDestPoint,
489 const RECT *pSourceRect )
490 {
491 struct pipe_context *pipe = This->pipe;
492 struct pipe_resource *r_dst = This->base.resource;
493 struct pipe_resource *r_src = From->base.resource;
494 struct pipe_transfer *transfer;
495 struct pipe_box src_box;
496 struct pipe_box dst_box;
497 uint8_t *p_dst;
498 const uint8_t *p_src;
499
500 DBG("This=%p From=%p pDestPoint=%p pSourceRect=%p\n",
501 This, From, pDestPoint, pSourceRect);
502
503 user_assert(This->desc.Format == From->desc.Format, D3DERR_INVALIDCALL);
504
505 dst_box.x = pDestPoint ? pDestPoint->x : 0;
506 dst_box.y = pDestPoint ? pDestPoint->y : 0;
507
508 user_assert(dst_box.x >= 0 &&
509 dst_box.y >= 0, D3DERR_INVALIDCALL);
510
511 dst_box.z = This->layer;
512 src_box.z = From->layer;
513
514 dst_box.depth = 1;
515 src_box.depth = 1;
516
517 if (pSourceRect) {
518 /* make sure it doesn't range outside the source surface */
519 user_assert(pSourceRect->left >= 0 &&
520 pSourceRect->right <= From->desc.Width &&
521 pSourceRect->top >= 0 &&
522 pSourceRect->bottom <= From->desc.Height,
523 D3DERR_INVALIDCALL);
524 if (rect_to_pipe_box_xy_only_clamp(&src_box, pSourceRect))
525 return D3D_OK;
526 } else {
527 src_box.x = 0;
528 src_box.y = 0;
529 src_box.width = From->desc.Width;
530 src_box.height = From->desc.Height;
531 }
532
533 /* limits */
534 dst_box.width = This->desc.Width - dst_box.x;
535 dst_box.height = This->desc.Height - dst_box.y;
536
537 user_assert(src_box.width <= dst_box.width &&
538 src_box.height <= dst_box.height, D3DERR_INVALIDCALL);
539
540 dst_box.width = src_box.width;
541 dst_box.height = src_box.height;
542
543 /* Don't copy to device memory of managed resources.
544 * We don't want to download it back again later.
545 */
546 if (This->base.pool == D3DPOOL_MANAGED)
547 r_dst = NULL;
548
549 /* Don't copy from stale device memory of managed resources.
550 * Also, don't copy between system and device if we don't have to.
551 */
552 if (From->base.pool == D3DPOOL_MANAGED) {
553 if (!r_dst || NineSurface9_IsDirty(From))
554 r_src = NULL;
555 }
556
557 /* check source block align for compressed textures */
558 if (util_format_is_compressed(From->base.info.format) &&
559 ((src_box.width != From->desc.Width) ||
560 (src_box.height != From->desc.Height))) {
561 const unsigned w = util_format_get_blockwidth(From->base.info.format);
562 const unsigned h = util_format_get_blockheight(From->base.info.format);
563 user_assert(!(src_box.width % w) &&
564 !(src_box.height % h),
565 D3DERR_INVALIDCALL);
566 }
567
568 /* check destination block align for compressed textures */
569 if (util_format_is_compressed(This->base.info.format) &&
570 ((dst_box.width != This->desc.Width) ||
571 (dst_box.height != This->desc.Height) ||
572 dst_box.x != 0 ||
573 dst_box.y != 0)) {
574 const unsigned w = util_format_get_blockwidth(This->base.info.format);
575 const unsigned h = util_format_get_blockheight(This->base.info.format);
576 user_assert(!(dst_box.x % w) && !(dst_box.width % w) &&
577 !(dst_box.y % h) && !(dst_box.height % h),
578 D3DERR_INVALIDCALL);
579 }
580
581 if (r_dst && r_src) {
582 pipe->resource_copy_region(pipe,
583 r_dst, This->level,
584 dst_box.x, dst_box.y, dst_box.z,
585 r_src, From->level,
586 &src_box);
587 } else
588 if (r_dst) {
589 p_src = NineSurface9_GetSystemMemPointer(From, src_box.x, src_box.y);
590
591 pipe->transfer_inline_write(pipe, r_dst, This->level,
592 0, /* WRITE|DISCARD are implicit */
593 &dst_box, p_src, From->stride, 0);
594 } else
595 if (r_src) {
596 p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0);
597
598 p_src = pipe->transfer_map(pipe, r_src, From->level,
599 PIPE_TRANSFER_READ,
600 &src_box, &transfer);
601 if (!p_src)
602 return D3DERR_DRIVERINTERNALERROR;
603
604 util_copy_rect(p_dst, This->base.info.format,
605 This->stride, dst_box.x, dst_box.y,
606 dst_box.width, dst_box.height,
607 p_src,
608 transfer->stride, src_box.x, src_box.y);
609
610 pipe->transfer_unmap(pipe, transfer);
611 } else {
612 p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0);
613 p_src = NineSurface9_GetSystemMemPointer(From, 0, 0);
614
615 util_copy_rect(p_dst, This->base.info.format,
616 This->stride, dst_box.x, dst_box.y,
617 dst_box.width, dst_box.height,
618 p_src,
619 From->stride, src_box.x, src_box.y);
620 }
621
622 if (This->base.pool == D3DPOOL_DEFAULT ||
623 This->base.pool == D3DPOOL_MANAGED)
624 NineSurface9_MarkContainerDirty(This);
625 if (!r_dst && This->base.resource)
626 NineSurface9_AddDirtyRect(This, &dst_box);
627
628 return D3D_OK;
629 }
630
631 /* Gladly, rendering to a MANAGED surface is not permitted, so we will
632 * never have to do the reverse, i.e. download the surface.
633 */
634 HRESULT
635 NineSurface9_UploadSelf( struct NineSurface9 *This )
636 {
637 struct pipe_context *pipe = This->pipe;
638 struct pipe_resource *res = This->base.resource;
639 uint8_t *ptr;
640 unsigned i;
641
642 DBG("This=%p\n", This);
643
644 assert(This->base.pool == D3DPOOL_MANAGED);
645
646 if (!NineSurface9_IsDirty(This))
647 return D3D_OK;
648
649 for (i = 0; i < Elements(This->dirty_rects); ++i) {
650 struct pipe_box box;
651 nine_u_rect_to_pipe_box(&box, &This->dirty_rects[i], This->layer);
652
653 if (box.width == 0)
654 break;
655 ptr = NineSurface9_GetSystemMemPointer(This, box.x, box.y);
656
657 pipe->transfer_inline_write(pipe, res, This->level,
658 0,
659 &box, ptr, This->stride, 0);
660 }
661 NineSurface9_ClearDirtyRects(This);
662
663 return D3D_OK;
664 }
665
666 void
667 NineSurface9_SetResourceResize( struct NineSurface9 *This,
668 struct pipe_resource *resource )
669 {
670 assert(This->level == 0 && This->level_actual == 0);
671 assert(!This->lock_count);
672 assert(This->desc.Pool == D3DPOOL_DEFAULT);
673 assert(!This->texture);
674
675 pipe_resource_reference(&This->base.resource, resource);
676
677 This->desc.Width = This->base.info.width0 = resource->width0;
678 This->desc.Height = This->base.info.height0 = resource->height0;
679
680 This->stride = util_format_get_stride(This->base.info.format,
681 This->desc.Width);
682 This->stride = align(This->stride, 4);
683
684 pipe_surface_reference(&This->surface[0], NULL);
685 pipe_surface_reference(&This->surface[1], NULL);
686 }
687
688
689 static const GUID *NineSurface9_IIDs[] = {
690 &IID_IDirect3DSurface9,
691 &IID_IDirect3DResource9,
692 &IID_IUnknown,
693 NULL
694 };
695
696 HRESULT
697 NineSurface9_new( struct NineDevice9 *pDevice,
698 struct NineUnknown *pContainer,
699 struct pipe_resource *pResource,
700 void *user_buffer,
701 uint8_t TextureType,
702 unsigned Level,
703 unsigned Layer,
704 D3DSURFACE_DESC *pDesc,
705 struct NineSurface9 **ppOut )
706 {
707 NINE_DEVICE_CHILD_NEW(Surface9, ppOut, pDevice, /* args */
708 pContainer, pResource, user_buffer,
709 TextureType, Level, Layer, pDesc);
710 }