2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2011, 2013-2014 Stefan Dösinger for CodeWeavers
10 * Copyright 2007-2008 Henri Verbeet
11 * Copyright 2006-2008 Roderick Colenbrander
12 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface
);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d
);
37 #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */
39 static const DWORD surface_simple_locations
=
40 WINED3D_LOCATION_SYSMEM
| WINED3D_LOCATION_USER_MEMORY
41 | WINED3D_LOCATION_DIB
| WINED3D_LOCATION_BUFFER
;
43 static void surface_cleanup(struct wined3d_surface
*surface
)
45 struct wined3d_surface
*overlay
, *cur
;
47 TRACE("surface %p.\n", surface
);
49 if (surface
->pbo
|| surface
->rb_multisample
50 || surface
->rb_resolved
|| !list_empty(&surface
->renderbuffers
))
52 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
53 const struct wined3d_gl_info
*gl_info
;
54 struct wined3d_context
*context
;
56 context
= context_acquire(surface
->resource
.device
, NULL
);
57 gl_info
= context
->gl_info
;
61 TRACE("Deleting PBO %u.\n", surface
->pbo
);
62 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
65 if (surface
->rb_multisample
)
67 TRACE("Deleting multisample renderbuffer %u.\n", surface
->rb_multisample
);
68 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
71 if (surface
->rb_resolved
)
73 TRACE("Deleting resolved renderbuffer %u.\n", surface
->rb_resolved
);
74 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
77 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
79 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
80 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
81 HeapFree(GetProcessHeap(), 0, entry
);
84 context_release(context
);
87 if (surface
->flags
& SFLAG_DIBSECTION
)
89 DeleteDC(surface
->hDC
);
90 DeleteObject(surface
->dib
.DIBsection
);
91 surface
->dib
.bitmap_data
= NULL
;
94 if (surface
->overlay_dest
)
95 list_remove(&surface
->overlay_entry
);
97 LIST_FOR_EACH_ENTRY_SAFE(overlay
, cur
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
99 list_remove(&overlay
->overlay_entry
);
100 overlay
->overlay_dest
= NULL
;
103 resource_cleanup(&surface
->resource
);
106 void surface_update_draw_binding(struct wined3d_surface
*surface
)
108 if (!surface_is_offscreen(surface
) || wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
)
109 surface
->draw_binding
= WINED3D_LOCATION_DRAWABLE
;
110 else if (surface
->resource
.multisample_type
)
111 surface
->draw_binding
= WINED3D_LOCATION_RB_MULTISAMPLE
;
113 surface
->draw_binding
= WINED3D_LOCATION_TEXTURE_RGB
;
116 void surface_set_swapchain(struct wined3d_surface
*surface
, struct wined3d_swapchain
*swapchain
)
118 TRACE("surface %p, swapchain %p.\n", surface
, swapchain
);
122 surface
->get_drawable_size
= get_drawable_size_swapchain
;
126 switch (wined3d_settings
.offscreen_rendering_mode
)
129 surface
->get_drawable_size
= get_drawable_size_fbo
;
133 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
137 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
142 surface
->swapchain
= swapchain
;
143 surface_update_draw_binding(surface
);
146 void surface_set_container(struct wined3d_surface
*surface
, struct wined3d_texture
*container
)
148 TRACE("surface %p, container %p.\n", surface
, container
);
150 if (!surface
->swapchain
)
152 switch (wined3d_settings
.offscreen_rendering_mode
)
155 surface
->get_drawable_size
= get_drawable_size_fbo
;
159 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
163 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
168 surface
->container
= container
;
169 surface_update_draw_binding(surface
);
176 enum tex_types tex_type
;
177 GLfloat coords
[4][3];
188 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
190 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
191 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
192 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
193 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
196 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
198 GLfloat (*coords
)[3] = info
->coords
;
204 FIXME("Unsupported texture target %#x\n", target
);
205 /* Fall back to GL_TEXTURE_2D */
207 info
->binding
= GL_TEXTURE_BINDING_2D
;
208 info
->bind_target
= GL_TEXTURE_2D
;
209 info
->tex_type
= tex_2d
;
210 coords
[0][0] = (float)rect
->left
/ w
;
211 coords
[0][1] = (float)rect
->top
/ h
;
214 coords
[1][0] = (float)rect
->right
/ w
;
215 coords
[1][1] = (float)rect
->top
/ h
;
218 coords
[2][0] = (float)rect
->left
/ w
;
219 coords
[2][1] = (float)rect
->bottom
/ h
;
222 coords
[3][0] = (float)rect
->right
/ w
;
223 coords
[3][1] = (float)rect
->bottom
/ h
;
227 case GL_TEXTURE_RECTANGLE_ARB
:
228 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
229 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
230 info
->tex_type
= tex_rect
;
231 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
232 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
233 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
234 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
237 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
238 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
239 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
240 info
->tex_type
= tex_cube
;
241 cube_coords_float(rect
, w
, h
, &f
);
243 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
244 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
245 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
246 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
249 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
250 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
251 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
252 info
->tex_type
= tex_cube
;
253 cube_coords_float(rect
, w
, h
, &f
);
255 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
256 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
257 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
258 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
261 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
262 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
263 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
264 info
->tex_type
= tex_cube
;
265 cube_coords_float(rect
, w
, h
, &f
);
267 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
268 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
269 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
270 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
273 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
274 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
275 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
276 info
->tex_type
= tex_cube
;
277 cube_coords_float(rect
, w
, h
, &f
);
279 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
280 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
281 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
282 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
285 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
286 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
287 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
288 info
->tex_type
= tex_cube
;
289 cube_coords_float(rect
, w
, h
, &f
);
291 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
292 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
293 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
294 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
297 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
298 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
299 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
300 info
->tex_type
= tex_cube
;
301 cube_coords_float(rect
, w
, h
, &f
);
303 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
304 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
305 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
306 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
311 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
314 *rect_out
= *rect_in
;
319 rect_out
->right
= surface
->resource
.width
;
320 rect_out
->bottom
= surface
->resource
.height
;
324 /* Context activation is done by the caller. */
325 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
326 const RECT
*src_rect
, const RECT
*dst_rect
, enum wined3d_texture_filter_type filter
)
328 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
329 struct wined3d_texture
*texture
= src_surface
->container
;
330 struct blt_info info
;
332 surface_get_blt_info(src_surface
->texture_target
, src_rect
, src_surface
->pow2Width
, src_surface
->pow2Height
, &info
);
334 gl_info
->gl_ops
.gl
.p_glEnable(info
.bind_target
);
335 checkGLcall("glEnable(bind_target)");
337 context_bind_texture(context
, info
.bind_target
, texture
->texture_rgb
.name
);
339 /* Filtering for StretchRect */
340 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
,
341 wined3d_gl_mag_filter(magLookup
, filter
));
342 checkGLcall("glTexParameteri");
343 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
344 wined3d_gl_min_mip_filter(minMipLookup
, filter
, WINED3D_TEXF_NONE
));
345 checkGLcall("glTexParameteri");
346 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
347 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
348 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
349 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
350 gl_info
->gl_ops
.gl
.p_glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
351 checkGLcall("glTexEnvi");
354 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
355 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
356 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->top
);
358 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
359 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->top
);
361 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
362 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
364 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
365 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
366 gl_info
->gl_ops
.gl
.p_glEnd();
368 /* Unbind the texture */
369 context_bind_texture(context
, info
.bind_target
, 0);
371 /* We changed the filtering settings on the texture. Inform the
372 * container about this to get the filters reset properly next draw. */
373 texture
->texture_rgb
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3D_TEXF_POINT
;
374 texture
->texture_rgb
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3D_TEXF_POINT
;
375 texture
->texture_rgb
.states
[WINED3DTEXSTA_MIPFILTER
] = WINED3D_TEXF_NONE
;
376 texture
->texture_rgb
.states
[WINED3DTEXSTA_SRGBTEXTURE
] = FALSE
;
379 /* Works correctly only for <= 4 bpp formats. */
380 static void get_color_masks(const struct wined3d_format
*format
, DWORD
*masks
)
382 masks
[0] = ((1 << format
->red_size
) - 1) << format
->red_offset
;
383 masks
[1] = ((1 << format
->green_size
) - 1) << format
->green_offset
;
384 masks
[2] = ((1 << format
->blue_size
) - 1) << format
->blue_offset
;
387 static HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
389 const struct wined3d_format
*format
= surface
->resource
.format
;
395 TRACE("surface %p.\n", surface
);
397 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
399 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
400 return WINED3DERR_INVALIDCALL
;
403 switch (format
->byte_count
)
407 /* Allocate extra space to store the RGB bit masks. */
408 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
412 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
416 /* Allocate extra space for a palette. */
417 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
418 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
423 return E_OUTOFMEMORY
;
425 /* Some applications access the surface in via DWORDs, and do not take
426 * the necessary care at the end of the surface. So we need at least
427 * 4 extra bytes at the end of the surface. Check against the page size,
428 * if the last page used for the surface has at least 4 spare bytes we're
429 * safe, otherwise add an extra line to the DIB section. */
430 GetSystemInfo(&sysInfo
);
431 if( ((surface
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4)
434 TRACE("Adding an extra line to the DIB section.\n");
437 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
438 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
439 b_info
->bmiHeader
.biWidth
= wined3d_surface_get_pitch(surface
) / format
->byte_count
;
440 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
- extraline
;
441 b_info
->bmiHeader
.biSizeImage
= (surface
->resource
.height
+ extraline
)
442 * wined3d_surface_get_pitch(surface
);
443 b_info
->bmiHeader
.biPlanes
= 1;
444 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
446 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
447 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
448 b_info
->bmiHeader
.biClrUsed
= 0;
449 b_info
->bmiHeader
.biClrImportant
= 0;
451 /* Get the bit masks */
452 masks
= (DWORD
*)b_info
->bmiColors
;
453 switch (surface
->resource
.format
->id
)
455 case WINED3DFMT_B8G8R8_UNORM
:
456 b_info
->bmiHeader
.biCompression
= BI_RGB
;
459 case WINED3DFMT_B5G5R5X1_UNORM
:
460 case WINED3DFMT_B5G5R5A1_UNORM
:
461 case WINED3DFMT_B4G4R4A4_UNORM
:
462 case WINED3DFMT_B4G4R4X4_UNORM
:
463 case WINED3DFMT_B2G3R3_UNORM
:
464 case WINED3DFMT_B2G3R3A8_UNORM
:
465 case WINED3DFMT_R10G10B10A2_UNORM
:
466 case WINED3DFMT_R8G8B8A8_UNORM
:
467 case WINED3DFMT_R8G8B8X8_UNORM
:
468 case WINED3DFMT_B10G10R10A2_UNORM
:
469 case WINED3DFMT_B5G6R5_UNORM
:
470 case WINED3DFMT_R16G16B16A16_UNORM
:
471 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
472 get_color_masks(format
, masks
);
476 /* Don't know palette */
477 b_info
->bmiHeader
.biCompression
= BI_RGB
;
481 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
482 b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
,
483 b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
484 surface
->dib
.DIBsection
= CreateDIBSection(0, b_info
, DIB_RGB_COLORS
, &surface
->dib
.bitmap_data
, 0, 0);
486 if (!surface
->dib
.DIBsection
)
488 ERR("Failed to create DIB section.\n");
489 HeapFree(GetProcessHeap(), 0, b_info
);
490 return HRESULT_FROM_WIN32(GetLastError());
493 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
494 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
496 HeapFree(GetProcessHeap(), 0, b_info
);
498 /* Now allocate a DC. */
499 surface
->hDC
= CreateCompatibleDC(0);
500 SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
502 surface
->flags
|= SFLAG_DIBSECTION
;
507 static void surface_get_memory(const struct wined3d_surface
*surface
, struct wined3d_bo_address
*data
,
510 if (location
& WINED3D_LOCATION_BUFFER
)
513 data
->buffer_object
= surface
->pbo
;
516 if (location
& WINED3D_LOCATION_USER_MEMORY
)
518 data
->addr
= surface
->user_memory
;
519 data
->buffer_object
= 0;
522 if (location
& WINED3D_LOCATION_DIB
)
524 data
->addr
= surface
->dib
.bitmap_data
;
525 data
->buffer_object
= 0;
528 if (location
& WINED3D_LOCATION_SYSMEM
)
530 data
->addr
= surface
->resource
.heap_memory
;
531 data
->buffer_object
= 0;
535 ERR("Unexpected locations %s.\n", wined3d_debug_location(location
));
537 data
->buffer_object
= 0;
540 static void surface_prepare_buffer(struct wined3d_surface
*surface
)
542 struct wined3d_context
*context
;
544 const struct wined3d_gl_info
*gl_info
;
549 context
= context_acquire(surface
->resource
.device
, NULL
);
550 gl_info
= context
->gl_info
;
552 GL_EXTCALL(glGenBuffersARB(1, &surface
->pbo
));
553 error
= gl_info
->gl_ops
.gl
.p_glGetError();
554 if (!surface
->pbo
|| error
!= GL_NO_ERROR
)
555 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error
), error
);
557 TRACE("Binding PBO %u.\n", surface
->pbo
);
559 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
560 checkGLcall("glBindBufferARB");
562 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->resource
.size
+ 4,
563 NULL
, GL_STREAM_DRAW_ARB
));
564 checkGLcall("glBufferDataARB");
566 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
567 checkGLcall("glBindBufferARB");
569 context_release(context
);
572 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
574 TRACE("surface %p.\n", surface
);
576 if (surface
->resource
.heap_memory
)
579 /* Whatever surface we have, make sure that there is memory allocated
580 * for the downloaded copy, or a PBO to map. */
581 if (!wined3d_resource_allocate_sysmem(&surface
->resource
))
582 ERR("Failed to allocate system memory.\n");
584 if (surface
->locations
& WINED3D_LOCATION_SYSMEM
)
585 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
588 void surface_prepare_map_memory(struct wined3d_surface
*surface
)
590 switch (surface
->map_binding
)
592 case WINED3D_LOCATION_SYSMEM
:
593 surface_prepare_system_memory(surface
);
596 case WINED3D_LOCATION_USER_MEMORY
:
597 if (!surface
->user_memory
)
598 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
601 case WINED3D_LOCATION_DIB
:
602 if (!surface
->dib
.bitmap_data
)
603 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
606 case WINED3D_LOCATION_BUFFER
:
607 surface_prepare_buffer(surface
);
611 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->map_binding
));
615 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
617 if (surface
->resource
.map_count
|| surface
->flags
& SFLAG_DONOTFREE
)
620 wined3d_resource_free_sysmem(&surface
->resource
);
621 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
624 static void surface_force_reload(struct wined3d_surface
*surface
)
626 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
629 static void surface_release_client_storage(struct wined3d_surface
*surface
)
631 struct wined3d_context
*context
= context_acquire(surface
->resource
.device
, NULL
);
632 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
634 if (surface
->container
->texture_rgb
.name
)
636 wined3d_texture_bind_and_dirtify(surface
->container
, context
, FALSE
);
637 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
638 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
640 if (surface
->container
->texture_srgb
.name
)
642 wined3d_texture_bind_and_dirtify(surface
->container
, context
, TRUE
);
643 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
644 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
647 context_release(context
);
649 surface_invalidate_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
);
650 surface_force_reload(surface
);
653 static BOOL
surface_use_pbo(const struct wined3d_surface
*surface
)
655 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
657 return surface
->resource
.pool
== WINED3D_POOL_DEFAULT
658 && surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
659 && gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
]
660 && !surface
->resource
.format
->convert
661 && !(surface
->flags
& (SFLAG_NONPOW2
| SFLAG_PIN_SYSMEM
));
664 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
666 /* TODO: Check against the maximum texture sizes supported by the video card. */
667 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
668 unsigned int pow2Width
, pow2Height
;
670 TRACE("surface %p.\n", surface
);
672 /* Non-power2 support */
673 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
]
674 || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
676 pow2Width
= surface
->resource
.width
;
677 pow2Height
= surface
->resource
.height
;
681 /* Find the nearest pow2 match */
682 pow2Width
= pow2Height
= 1;
683 while (pow2Width
< surface
->resource
.width
)
685 while (pow2Height
< surface
->resource
.height
)
688 surface
->pow2Width
= pow2Width
;
689 surface
->pow2Height
= pow2Height
;
691 if (pow2Width
> surface
->resource
.width
|| pow2Height
> surface
->resource
.height
)
693 /* TODO: Add support for non power two compressed textures. */
694 if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_HEIGHT_SCALE
))
696 FIXME("(%p) Compressed or height scaled non-power-two textures are not supported w(%d) h(%d)\n",
697 surface
, surface
->resource
.width
, surface
->resource
.height
);
698 return WINED3DERR_NOTAVAILABLE
;
702 if (pow2Width
!= surface
->resource
.width
703 || pow2Height
!= surface
->resource
.height
)
705 surface
->flags
|= SFLAG_NONPOW2
;
708 if ((surface
->pow2Width
> gl_info
->limits
.texture_size
|| surface
->pow2Height
> gl_info
->limits
.texture_size
)
709 && !(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
711 /* One of three options:
712 * 1: Do the same as we do with NPOT and scale the texture, (any
713 * texture ops would require the texture to be scaled which is
715 * 2: Set the texture to the maximum size (bad idea).
716 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
717 * 4: Create the surface, but allow it to be used only for DirectDraw
718 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
719 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
720 * the render target. */
721 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
|| surface
->resource
.pool
== WINED3D_POOL_MANAGED
)
723 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
724 return WINED3DERR_NOTAVAILABLE
;
727 /* We should never use this surface in combination with OpenGL! */
728 TRACE("Creating an oversized surface: %ux%u.\n",
729 surface
->pow2Width
, surface
->pow2Height
);
732 switch (wined3d_settings
.offscreen_rendering_mode
)
735 surface
->get_drawable_size
= get_drawable_size_fbo
;
739 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
743 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
744 return WINED3DERR_INVALIDCALL
;
747 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
748 surface
->locations
= WINED3D_LOCATION_DISCARDED
;
750 if (surface_use_pbo(surface
))
751 surface
->map_binding
= WINED3D_LOCATION_BUFFER
;
756 static void surface_unmap(struct wined3d_surface
*surface
)
758 struct wined3d_device
*device
= surface
->resource
.device
;
759 const struct wined3d_gl_info
*gl_info
;
760 struct wined3d_context
*context
;
762 TRACE("surface %p.\n", surface
);
764 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
766 switch (surface
->map_binding
)
768 case WINED3D_LOCATION_SYSMEM
:
769 case WINED3D_LOCATION_USER_MEMORY
:
770 case WINED3D_LOCATION_DIB
:
773 case WINED3D_LOCATION_BUFFER
:
774 context
= context_acquire(device
, NULL
);
775 gl_info
= context
->gl_info
;
777 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
778 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
779 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
780 checkGLcall("glUnmapBufferARB");
781 context_release(context
);
785 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->map_binding
));
788 if (surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_TEXTURE_RGB
))
790 TRACE("Not dirtified, nothing to do.\n");
794 if (surface
->swapchain
&& surface
->swapchain
->front_buffer
== surface
)
795 surface_load_location(surface
, surface
->draw_binding
);
796 else if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
797 FIXME("Depth / stencil buffer locking is not implemented.\n");
800 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
802 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
804 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
809 static void surface_depth_blt_fbo(const struct wined3d_device
*device
,
810 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
811 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
813 const struct wined3d_gl_info
*gl_info
;
814 struct wined3d_context
*context
;
815 DWORD src_mask
, dst_mask
;
818 TRACE("device %p\n", device
);
819 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
820 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect
));
821 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
822 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect
));
824 src_mask
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
825 dst_mask
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
827 if (src_mask
!= dst_mask
)
829 ERR("Incompatible formats %s and %s.\n",
830 debug_d3dformat(src_surface
->resource
.format
->id
),
831 debug_d3dformat(dst_surface
->resource
.format
->id
));
837 ERR("Not a depth / stencil format: %s.\n",
838 debug_d3dformat(src_surface
->resource
.format
->id
));
843 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
844 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
845 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
846 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
848 /* Make sure the locations are up-to-date. Loading the destination
849 * surface isn't required if the entire surface is overwritten. */
850 surface_load_location(src_surface
, src_location
);
851 if (!surface_is_full_rect(dst_surface
, dst_rect
))
852 surface_load_location(dst_surface
, dst_location
);
854 context
= context_acquire(device
, NULL
);
857 context_release(context
);
858 WARN("Invalid context, skipping blit.\n");
862 gl_info
= context
->gl_info
;
864 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, src_location
);
865 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
867 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, dst_location
);
868 context_set_draw_buffer(context
, GL_NONE
);
869 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
870 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
872 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
874 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
875 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
877 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
879 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
881 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
882 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
884 gl_info
->gl_ops
.gl
.p_glStencilMask(~0U);
885 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
888 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
889 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
891 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
892 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
893 checkGLcall("glBlitFramebuffer()");
895 if (wined3d_settings
.strict_draw_ordering
)
896 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
898 context_release(context
);
901 /* Blit between surface locations. Onscreen on different swapchains is not supported.
902 * Depth / stencil is not supported. */
903 static void surface_blt_fbo(const struct wined3d_device
*device
, enum wined3d_texture_filter_type filter
,
904 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
905 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
907 const struct wined3d_gl_info
*gl_info
;
908 struct wined3d_context
*context
;
909 RECT src_rect
, dst_rect
;
913 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
914 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
915 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect_in
));
916 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
917 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect_in
));
919 src_rect
= *src_rect_in
;
920 dst_rect
= *dst_rect_in
;
924 case WINED3D_TEXF_LINEAR
:
925 gl_filter
= GL_LINEAR
;
929 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
930 case WINED3D_TEXF_NONE
:
931 case WINED3D_TEXF_POINT
:
932 gl_filter
= GL_NEAREST
;
936 /* Resolve the source surface first if needed. */
937 if (src_location
== WINED3D_LOCATION_RB_MULTISAMPLE
938 && (src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
939 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
940 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
941 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
943 /* Make sure the locations are up-to-date. Loading the destination
944 * surface isn't required if the entire surface is overwritten. (And is
945 * in fact harmful if we're being called by surface_load_location() with
946 * the purpose of loading the destination surface.) */
947 surface_load_location(src_surface
, src_location
);
948 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
949 surface_load_location(dst_surface
, dst_location
);
951 if (src_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, src_surface
);
952 else if (dst_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, dst_surface
);
953 else context
= context_acquire(device
, NULL
);
957 context_release(context
);
958 WARN("Invalid context, skipping blit.\n");
962 gl_info
= context
->gl_info
;
964 if (src_location
== WINED3D_LOCATION_DRAWABLE
)
966 TRACE("Source surface %p is onscreen.\n", src_surface
);
967 buffer
= surface_get_gl_buffer(src_surface
);
968 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
972 TRACE("Source surface %p is offscreen.\n", src_surface
);
973 buffer
= GL_COLOR_ATTACHMENT0
;
976 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
977 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
978 checkGLcall("glReadBuffer()");
979 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
981 if (dst_location
== WINED3D_LOCATION_DRAWABLE
)
983 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
984 buffer
= surface_get_gl_buffer(dst_surface
);
985 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
989 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
990 buffer
= GL_COLOR_ATTACHMENT0
;
993 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
994 context_set_draw_buffer(context
, buffer
);
995 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
996 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
998 gl_info
->gl_ops
.gl
.p_glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
999 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
1000 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
1001 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
1002 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
1004 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
1005 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
1007 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
1008 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
1009 checkGLcall("glBlitFramebuffer()");
1011 if (wined3d_settings
.strict_draw_ordering
1012 || (dst_location
== WINED3D_LOCATION_DRAWABLE
1013 && dst_surface
->swapchain
->front_buffer
== dst_surface
))
1014 gl_info
->gl_ops
.gl
.p_glFlush();
1016 context_release(context
);
1019 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
1020 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
1021 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
1023 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
1026 /* Source and/or destination need to be on the GL side */
1027 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
1032 case WINED3D_BLIT_OP_COLOR_BLIT
:
1033 if (!((src_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
1035 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
1039 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1040 if (!(src_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1042 if (!(dst_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1050 if (!(src_format
->id
== dst_format
->id
1051 || (is_identity_fixup(src_format
->color_fixup
)
1052 && is_identity_fixup(dst_format
->color_fixup
))))
1058 static BOOL
surface_convert_color_to_float(const struct wined3d_surface
*surface
,
1059 DWORD color
, struct wined3d_color
*float_color
)
1061 const struct wined3d_format
*format
= surface
->resource
.format
;
1062 const struct wined3d_palette
*palette
;
1066 case WINED3DFMT_P8_UINT
:
1067 palette
= surface
->swapchain
? surface
->swapchain
->palette
: NULL
;
1071 float_color
->r
= palette
->colors
[color
].rgbRed
/ 255.0f
;
1072 float_color
->g
= palette
->colors
[color
].rgbGreen
/ 255.0f
;
1073 float_color
->b
= palette
->colors
[color
].rgbBlue
/ 255.0f
;
1077 float_color
->r
= 0.0f
;
1078 float_color
->g
= 0.0f
;
1079 float_color
->b
= 0.0f
;
1081 float_color
->a
= color
/ 255.0f
;
1084 case WINED3DFMT_B5G6R5_UNORM
:
1085 float_color
->r
= ((color
>> 11) & 0x1f) / 31.0f
;
1086 float_color
->g
= ((color
>> 5) & 0x3f) / 63.0f
;
1087 float_color
->b
= (color
& 0x1f) / 31.0f
;
1088 float_color
->a
= 1.0f
;
1091 case WINED3DFMT_B8G8R8_UNORM
:
1092 case WINED3DFMT_B8G8R8X8_UNORM
:
1093 float_color
->r
= D3DCOLOR_R(color
);
1094 float_color
->g
= D3DCOLOR_G(color
);
1095 float_color
->b
= D3DCOLOR_B(color
);
1096 float_color
->a
= 1.0f
;
1099 case WINED3DFMT_B8G8R8A8_UNORM
:
1100 float_color
->r
= D3DCOLOR_R(color
);
1101 float_color
->g
= D3DCOLOR_G(color
);
1102 float_color
->b
= D3DCOLOR_B(color
);
1103 float_color
->a
= D3DCOLOR_A(color
);
1107 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1114 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1116 const struct wined3d_format
*format
= surface
->resource
.format
;
1120 case WINED3DFMT_S1_UINT_D15_UNORM
:
1121 *float_depth
= depth
/ (float)0x00007fff;
1124 case WINED3DFMT_D16_UNORM
:
1125 *float_depth
= depth
/ (float)0x0000ffff;
1128 case WINED3DFMT_D24_UNORM_S8_UINT
:
1129 case WINED3DFMT_X8D24_UNORM
:
1130 *float_depth
= depth
/ (float)0x00ffffff;
1133 case WINED3DFMT_D32_UNORM
:
1134 *float_depth
= depth
/ (float)0xffffffff;
1138 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1145 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1147 const struct wined3d_resource
*resource
= &surface
->resource
;
1148 struct wined3d_device
*device
= resource
->device
;
1149 const struct blit_shader
*blitter
;
1151 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_FILL
,
1152 NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
);
1155 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1156 return WINED3DERR_INVALIDCALL
;
1159 return blitter
->depth_fill(device
, surface
, rect
, depth
);
1162 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
1163 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
1165 struct wined3d_device
*device
= src_surface
->resource
.device
;
1167 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1168 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1169 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1170 return WINED3DERR_INVALIDCALL
;
1172 surface_depth_blt_fbo(device
, src_surface
, src_location
, src_rect
, dst_surface
, dst_location
, dst_rect
);
1174 surface_modify_ds_location(dst_surface
, dst_location
,
1175 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1180 HRESULT CDECL
wined3d_surface_get_render_target_data(struct wined3d_surface
*surface
,
1181 struct wined3d_surface
*render_target
)
1183 TRACE("surface %p, render_target %p.\n", surface
, render_target
);
1185 /* TODO: Check surface sizes, pools, etc. */
1187 if (render_target
->resource
.multisample_type
)
1188 return WINED3DERR_INVALIDCALL
;
1190 return wined3d_surface_blt(surface
, NULL
, render_target
, NULL
, 0, NULL
, WINED3D_TEXF_POINT
);
1193 /* Context activation is done by the caller. */
1194 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1196 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
1197 checkGLcall("glDeleteBuffersARB(1, &surface->pbo)");
1200 surface_invalidate_location(surface
, WINED3D_LOCATION_BUFFER
);
1203 static void surface_unload(struct wined3d_resource
*resource
)
1205 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1206 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1207 struct wined3d_device
*device
= resource
->device
;
1208 const struct wined3d_gl_info
*gl_info
;
1209 struct wined3d_context
*context
;
1211 TRACE("surface %p.\n", surface
);
1213 if (resource
->pool
== WINED3D_POOL_DEFAULT
)
1215 /* Default pool resources are supposed to be destroyed before Reset is called.
1216 * Implicit resources stay however. So this means we have an implicit render target
1217 * or depth stencil. The content may be destroyed, but we still have to tear down
1218 * opengl resources, so we cannot leave early.
1220 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1221 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1222 * or the depth stencil into an FBO the texture or render buffer will be removed
1223 * and all flags get lost */
1224 surface_prepare_system_memory(surface
);
1225 memset(surface
->resource
.heap_memory
, 0, surface
->resource
.size
);
1226 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
1227 surface_invalidate_location(surface
, ~WINED3D_LOCATION_SYSMEM
);
1229 /* We also get here when the ddraw swapchain is destroyed, for example
1230 * for a mode switch. In this case this surface won't necessarily be
1231 * an implicit surface. We have to mark it lost so that the
1232 * application can restore it after the mode switch. */
1233 surface
->flags
|= SFLAG_LOST
;
1237 surface_prepare_map_memory(surface
);
1238 surface_load_location(surface
, surface
->map_binding
);
1239 surface_invalidate_location(surface
, ~surface
->map_binding
);
1241 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
1243 context
= context_acquire(device
, NULL
);
1244 gl_info
= context
->gl_info
;
1246 /* Destroy PBOs, but load them into real sysmem before */
1248 surface_remove_pbo(surface
, gl_info
);
1250 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1251 * all application-created targets the application has to release the surface
1252 * before calling _Reset
1254 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1256 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1257 list_remove(&entry
->entry
);
1258 HeapFree(GetProcessHeap(), 0, entry
);
1260 list_init(&surface
->renderbuffers
);
1261 surface
->current_renderbuffer
= NULL
;
1263 if (surface
->rb_multisample
)
1265 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
1266 surface
->rb_multisample
= 0;
1268 if (surface
->rb_resolved
)
1270 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
1271 surface
->rb_resolved
= 0;
1274 context_release(context
);
1276 resource_unload(resource
);
1279 static const struct wined3d_resource_ops surface_resource_ops
=
1284 static const struct wined3d_surface_ops surface_ops
=
1286 surface_private_setup
,
1290 /*****************************************************************************
1291 * Initializes the GDI surface, aka creates the DIB section we render to
1292 * The DIB section creation is done by calling GetDC, which will create the
1293 * section and releasing the dc to allow the app to use it. The dib section
1294 * will stay until the surface is released
1296 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1297 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1298 * avoid confusion in the shared surface code.
1301 * WINED3D_OK on success
1302 * The return values of called methods on failure
1304 *****************************************************************************/
1305 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1309 TRACE("surface %p.\n", surface
);
1311 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1313 ERR("Overlays not yet supported by GDI surfaces.\n");
1314 return WINED3DERR_INVALIDCALL
;
1317 /* Sysmem textures have memory already allocated - release it,
1318 * this avoids an unnecessary memcpy. */
1319 hr
= surface_create_dib_section(surface
);
1322 surface
->map_binding
= WINED3D_LOCATION_DIB
;
1324 /* We don't mind the nonpow2 stuff in GDI. */
1325 surface
->pow2Width
= surface
->resource
.width
;
1326 surface
->pow2Height
= surface
->resource
.height
;
1331 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
1333 TRACE("surface %p.\n", surface
);
1335 /* Tell the swapchain to update the screen. */
1336 if (surface
->swapchain
&& surface
== surface
->swapchain
->front_buffer
)
1337 x11_copy_to_screen(surface
->swapchain
, &surface
->lockedRect
);
1339 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
1342 static const struct wined3d_surface_ops gdi_surface_ops
=
1344 gdi_surface_private_setup
,
1348 /* This call just downloads data, the caller is responsible for binding the
1349 * correct texture. */
1350 /* Context activation is done by the caller. */
1351 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1354 const struct wined3d_format
*format
= surface
->resource
.format
;
1355 struct wined3d_bo_address data
;
1357 /* Only support read back of converted P8 surfaces. */
1358 if (surface
->flags
& SFLAG_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
1360 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
1364 surface_get_memory(surface
, &data
, dst_location
);
1366 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1368 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
1369 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, data
.addr
);
1371 if (data
.buffer_object
)
1373 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
1374 checkGLcall("glBindBufferARB");
1375 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
, surface
->texture_level
, NULL
));
1376 checkGLcall("glGetCompressedTexImageARB");
1377 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
1378 checkGLcall("glBindBufferARB");
1382 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
,
1383 surface
->texture_level
, data
.addr
));
1384 checkGLcall("glGetCompressedTexImageARB");
1390 GLenum gl_format
= format
->glFormat
;
1391 GLenum gl_type
= format
->glType
;
1395 if (surface
->flags
& SFLAG_NONPOW2
)
1397 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
1398 src_pitch
= format
->byte_count
* surface
->pow2Width
;
1399 dst_pitch
= wined3d_surface_get_pitch(surface
);
1400 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
1401 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
1408 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1409 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
1411 if (data
.buffer_object
)
1413 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
1414 checkGLcall("glBindBufferARB");
1416 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1417 gl_format
, gl_type
, NULL
);
1418 checkGLcall("glGetTexImage");
1420 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
1421 checkGLcall("glBindBufferARB");
1425 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1426 gl_format
, gl_type
, mem
);
1427 checkGLcall("glGetTexImage");
1430 if (surface
->flags
& SFLAG_NONPOW2
)
1432 const BYTE
*src_data
;
1436 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1437 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1438 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1440 * We're doing this...
1442 * instead of boxing the texture :
1443 * |<-texture width ->| -->pow2width| /\
1444 * |111111111111111111| | |
1445 * |222 Texture 222222| boxed empty | texture height
1446 * |3333 Data 33333333| | |
1447 * |444444444444444444| | \/
1448 * ----------------------------------- |
1449 * | boxed empty | boxed empty | pow2height
1451 * -----------------------------------
1454 * we're repacking the data to the expected texture width
1456 * |<-texture width ->| -->pow2width| /\
1457 * |111111111111111111222222222222222| |
1458 * |222333333333333333333444444444444| texture height
1462 * | empty | pow2height
1464 * -----------------------------------
1468 * |<-texture width ->| /\
1469 * |111111111111111111|
1470 * |222222222222222222|texture height
1471 * |333333333333333333|
1472 * |444444444444444444| \/
1473 * --------------------
1475 * This also means that any references to surface memory should work with the data as if it were a
1476 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1478 * internally the texture is still stored in a boxed format so any references to textureName will
1479 * get a boxed texture with width pow2width and not a texture of width resource.width.
1481 * Performance should not be an issue, because applications normally do not lock the surfaces when
1482 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
1483 * and doesn't have to be re-read. */
1485 dst_data
= data
.addr
;
1486 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_pitch
);
1487 for (y
= 0; y
< surface
->resource
.height
; ++y
)
1489 memcpy(dst_data
, src_data
, dst_pitch
);
1490 src_data
+= src_pitch
;
1491 dst_data
+= dst_pitch
;
1494 HeapFree(GetProcessHeap(), 0, mem
);
1499 /* This call just uploads data, the caller is responsible for binding the
1500 * correct texture. */
1501 /* Context activation is done by the caller. */
1502 static void surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1503 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
1504 BOOL srgb
, const struct wined3d_bo_address
*data
)
1506 UINT update_w
= src_rect
->right
- src_rect
->left
;
1507 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
1509 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1510 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
1511 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
1513 if (surface
->resource
.map_count
)
1515 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
1516 surface
->flags
|= SFLAG_PIN_SYSMEM
;
1519 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
1521 update_h
*= format
->height_scale
.numerator
;
1522 update_h
/= format
->height_scale
.denominator
;
1525 if (data
->buffer_object
)
1527 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, data
->buffer_object
));
1528 checkGLcall("glBindBufferARB");
1531 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1533 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1, 1);
1534 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
1535 const BYTE
*addr
= data
->addr
;
1538 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
1539 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
1542 internal
= format
->glGammaInternal
;
1543 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
1544 internal
= format
->rtInternal
;
1546 internal
= format
->glInternal
;
1548 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
1549 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
1550 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
1552 if (row_length
== src_pitch
)
1554 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1555 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
1561 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
1562 * can't use the unpack row length like below. */
1563 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
1565 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1566 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
1567 y
+= format
->block_height
;
1571 checkGLcall("glCompressedTexSubImage2DARB");
1575 const BYTE
*addr
= data
->addr
;
1577 addr
+= src_rect
->top
* src_pitch
;
1578 addr
+= src_rect
->left
* format
->byte_count
;
1580 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1581 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
1582 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1584 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
1585 gl_info
->gl_ops
.gl
.p_glTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1586 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1587 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1588 checkGLcall("glTexSubImage2D");
1591 if (data
->buffer_object
)
1593 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
1594 checkGLcall("glBindBufferARB");
1597 if (wined3d_settings
.strict_draw_ordering
)
1598 gl_info
->gl_ops
.gl
.p_glFlush();
1600 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
1602 struct wined3d_device
*device
= surface
->resource
.device
;
1605 for (i
= 0; i
< device
->context_count
; ++i
)
1607 context_surface_update(device
->contexts
[i
], surface
);
1612 static HRESULT
d3dfmt_get_conv(const struct wined3d_surface
*surface
, BOOL need_alpha_ck
, BOOL use_texturing
,
1613 struct wined3d_format
*format
, enum wined3d_conversion_type
*conversion_type
)
1615 BOOL colorkey_active
= need_alpha_ck
&& (surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
);
1616 const struct wined3d_device
*device
= surface
->resource
.device
;
1617 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1618 BOOL blit_supported
= FALSE
;
1620 /* Copy the default values from the surface. Below we might perform fixups */
1621 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
1622 *format
= *surface
->resource
.format
;
1623 *conversion_type
= WINED3D_CT_NONE
;
1625 /* Ok, now look if we have to do any conversion */
1626 switch (surface
->resource
.format
->id
)
1628 case WINED3DFMT_P8_UINT
:
1629 /* Below the call to blit_supported is disabled for Wine 1.2
1630 * because the function isn't operating correctly yet. At the
1631 * moment 8-bit blits are handled in software and if certain GL
1632 * extensions are around, surface conversion is performed at
1633 * upload time. The blit_supported call recognizes it as a
1634 * destination fixup. This type of upload 'fixup' and 8-bit to
1635 * 8-bit blits need to be handled by the blit_shader.
1636 * TODO: get rid of this #if 0. */
1638 blit_supported
= device
->blitter
->blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
1639 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
1640 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
);
1642 blit_supported
= gl_info
->supported
[ARB_FRAGMENT_PROGRAM
];
1644 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
1645 * texturing. Further also use conversion in case of color keying.
1646 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
1647 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
1648 * conflicts with this.
1650 if (!((blit_supported
&& surface
->swapchain
&& surface
== surface
->swapchain
->front_buffer
))
1651 || colorkey_active
|| !use_texturing
)
1653 format
->glFormat
= GL_RGBA
;
1654 format
->glInternal
= GL_RGBA
;
1655 format
->glType
= GL_UNSIGNED_BYTE
;
1656 format
->conv_byte_count
= 4;
1657 *conversion_type
= WINED3D_CT_PALETTED
;
1661 case WINED3DFMT_B2G3R3_UNORM
:
1662 /* **********************
1663 GL_UNSIGNED_BYTE_3_3_2
1664 ********************** */
1665 if (colorkey_active
) {
1666 /* This texture format will never be used.. So do not care about color keying
1667 up until the point in time it will be needed :-) */
1668 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1672 case WINED3DFMT_B5G6R5_UNORM
:
1673 if (colorkey_active
)
1675 *conversion_type
= WINED3D_CT_CK_565
;
1676 format
->glFormat
= GL_RGBA
;
1677 format
->glInternal
= GL_RGB5_A1
;
1678 format
->glType
= GL_UNSIGNED_SHORT_5_5_5_1
;
1679 format
->conv_byte_count
= 2;
1683 case WINED3DFMT_B5G5R5X1_UNORM
:
1684 if (colorkey_active
)
1686 *conversion_type
= WINED3D_CT_CK_5551
;
1687 format
->glFormat
= GL_BGRA
;
1688 format
->glInternal
= GL_RGB5_A1
;
1689 format
->glType
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
1690 format
->conv_byte_count
= 2;
1694 case WINED3DFMT_B8G8R8_UNORM
:
1695 if (colorkey_active
)
1697 *conversion_type
= WINED3D_CT_CK_RGB24
;
1698 format
->glFormat
= GL_RGBA
;
1699 format
->glInternal
= GL_RGBA8
;
1700 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
1701 format
->conv_byte_count
= 4;
1705 case WINED3DFMT_B8G8R8X8_UNORM
:
1706 if (colorkey_active
)
1708 *conversion_type
= WINED3D_CT_RGB32_888
;
1709 format
->glFormat
= GL_RGBA
;
1710 format
->glInternal
= GL_RGBA8
;
1711 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
1712 format
->conv_byte_count
= 4;
1716 case WINED3DFMT_B8G8R8A8_UNORM
:
1717 if (colorkey_active
)
1719 *conversion_type
= WINED3D_CT_CK_ARGB32
;
1720 format
->conv_byte_count
= 4;
1728 if (*conversion_type
!= WINED3D_CT_NONE
)
1730 format
->rtInternal
= format
->glInternal
;
1731 format
->glGammaInternal
= format
->glInternal
;
1737 static BOOL
surface_check_block_align(struct wined3d_surface
*surface
, const RECT
*rect
)
1739 UINT width_mask
, height_mask
;
1741 if (!rect
->left
&& !rect
->top
1742 && rect
->right
== surface
->resource
.width
1743 && rect
->bottom
== surface
->resource
.height
)
1746 /* This assumes power of two block sizes, but NPOT block sizes would be
1748 width_mask
= surface
->resource
.format
->block_width
- 1;
1749 height_mask
= surface
->resource
.format
->block_height
- 1;
1751 if (!(rect
->left
& width_mask
) && !(rect
->top
& height_mask
)
1752 && !(rect
->right
& width_mask
) && !(rect
->bottom
& height_mask
))
1758 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
1759 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
1761 const struct wined3d_format
*src_format
;
1762 const struct wined3d_format
*dst_format
;
1763 const struct wined3d_gl_info
*gl_info
;
1764 enum wined3d_conversion_type convert
;
1765 struct wined3d_context
*context
;
1766 struct wined3d_bo_address data
;
1767 struct wined3d_format format
;
1768 UINT update_w
, update_h
;
1774 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1775 dst_surface
, wine_dbgstr_point(dst_point
),
1776 src_surface
, wine_dbgstr_rect(src_rect
));
1778 src_format
= src_surface
->resource
.format
;
1779 dst_format
= dst_surface
->resource
.format
;
1781 if (src_format
->id
!= dst_format
->id
)
1783 WARN("Source and destination surfaces should have the same format.\n");
1784 return WINED3DERR_INVALIDCALL
;
1793 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
1795 WARN("Invalid destination point.\n");
1796 return WINED3DERR_INVALIDCALL
;
1803 r
.right
= src_surface
->resource
.width
;
1804 r
.bottom
= src_surface
->resource
.height
;
1807 else if (src_rect
->left
< 0 || src_rect
->left
>= src_rect
->right
1808 || src_rect
->top
< 0 || src_rect
->top
>= src_rect
->bottom
)
1810 WARN("Invalid source rectangle.\n");
1811 return WINED3DERR_INVALIDCALL
;
1814 dst_w
= dst_surface
->resource
.width
;
1815 dst_h
= dst_surface
->resource
.height
;
1817 update_w
= src_rect
->right
- src_rect
->left
;
1818 update_h
= src_rect
->bottom
- src_rect
->top
;
1820 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
1821 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
1823 WARN("Destination out of bounds.\n");
1824 return WINED3DERR_INVALIDCALL
;
1827 if ((src_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(src_surface
, src_rect
))
1829 WARN("Source rectangle not block-aligned.\n");
1830 return WINED3DERR_INVALIDCALL
;
1833 SetRect(&dst_rect
, dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
);
1834 if ((dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(dst_surface
, &dst_rect
))
1836 WARN("Destination rectangle not block-aligned.\n");
1837 return WINED3DERR_INVALIDCALL
;
1840 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1841 d3dfmt_get_conv(dst_surface
, FALSE
, TRUE
, &format
, &convert
);
1842 if (convert
!= WINED3D_CT_NONE
|| format
.convert
)
1843 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
1845 context
= context_acquire(dst_surface
->resource
.device
, NULL
);
1846 gl_info
= context
->gl_info
;
1848 /* Only load the surface for partial updates. For newly allocated texture
1849 * the texture wouldn't be the current location, and we'd upload zeroes
1850 * just to overwrite them again. */
1851 if (update_w
== dst_w
&& update_h
== dst_h
)
1852 surface_prepare_texture(dst_surface
, context
, FALSE
);
1854 surface_load_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1855 wined3d_texture_bind(dst_surface
->container
, context
, FALSE
);
1857 surface_get_memory(src_surface
, &data
, src_surface
->locations
);
1858 src_pitch
= wined3d_surface_get_pitch(src_surface
);
1860 surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
, src_pitch
, dst_point
, FALSE
, &data
);
1862 context_invalidate_active_texture(context
);
1864 context_release(context
);
1866 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1867 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1872 /* This call just allocates the texture, the caller is responsible for binding
1873 * the correct texture. */
1874 /* Context activation is done by the caller. */
1875 static void surface_allocate_surface(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1876 const struct wined3d_format
*format
, BOOL srgb
)
1878 BOOL disable_client_storage
= FALSE
;
1879 GLsizei width
= surface
->pow2Width
;
1880 GLsizei height
= surface
->pow2Height
;
1881 const BYTE
*mem
= NULL
;
1886 internal
= format
->glGammaInternal
;
1888 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
1890 internal
= format
->rtInternal
;
1894 internal
= format
->glInternal
;
1898 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format
->id
));
1900 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
1902 height
*= format
->height_scale
.numerator
;
1903 height
/= format
->height_scale
.denominator
;
1906 TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n",
1907 surface
, surface
->texture_target
, surface
->texture_level
, debug_d3dformat(format
->id
),
1908 internal
, width
, height
, format
->glFormat
, format
->glType
);
1910 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1912 if (surface
->flags
& (SFLAG_NONPOW2
| SFLAG_DIBSECTION
| SFLAG_CONVERTED
)
1913 || !surface
->resource
.heap_memory
)
1915 /* In some cases we want to disable client storage.
1916 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
1917 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
1918 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
1919 * heap_memory == NULL: Not defined in the extension. Seems to disable client storage effectively
1921 surface
->flags
&= ~SFLAG_CLIENT
;
1925 surface
->flags
|= SFLAG_CLIENT
;
1926 mem
= surface
->resource
.heap_memory
;
1928 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
1929 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1930 disable_client_storage
= TRUE
;
1934 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
&& mem
)
1936 GL_EXTCALL(glCompressedTexImage2DARB(surface
->texture_target
, surface
->texture_level
,
1937 internal
, width
, height
, 0, surface
->resource
.size
, mem
));
1938 checkGLcall("glCompressedTexImage2DARB");
1942 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
1943 internal
, width
, height
, 0, format
->glFormat
, format
->glType
, mem
);
1944 checkGLcall("glTexImage2D");
1947 if (disable_client_storage
)
1949 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
1950 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1954 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1955 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1956 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1957 /* Context activation is done by the caller. */
1958 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
1960 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
1961 struct wined3d_renderbuffer_entry
*entry
;
1962 GLuint renderbuffer
= 0;
1963 unsigned int src_width
, src_height
;
1964 unsigned int width
, height
;
1966 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
1968 width
= rt
->pow2Width
;
1969 height
= rt
->pow2Height
;
1973 width
= surface
->pow2Width
;
1974 height
= surface
->pow2Height
;
1977 src_width
= surface
->pow2Width
;
1978 src_height
= surface
->pow2Height
;
1980 /* A depth stencil smaller than the render target is not valid */
1981 if (width
> src_width
|| height
> src_height
) return;
1983 /* Remove any renderbuffer set if the sizes match */
1984 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
1985 || (width
== src_width
&& height
== src_height
))
1987 surface
->current_renderbuffer
= NULL
;
1991 /* Look if we've already got a renderbuffer of the correct dimensions */
1992 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1994 if (entry
->width
== width
&& entry
->height
== height
)
1996 renderbuffer
= entry
->id
;
1997 surface
->current_renderbuffer
= entry
;
2004 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
2005 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
2006 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
2007 surface
->resource
.format
->glInternal
, width
, height
);
2009 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
2010 entry
->width
= width
;
2011 entry
->height
= height
;
2012 entry
->id
= renderbuffer
;
2013 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
2015 surface
->current_renderbuffer
= entry
;
2018 checkGLcall("set_compatible_renderbuffer");
2021 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
2023 const struct wined3d_swapchain
*swapchain
= surface
->swapchain
;
2025 TRACE("surface %p.\n", surface
);
2029 ERR("Surface %p is not on a swapchain.\n", surface
);
2033 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
)
2035 if (swapchain
->render_to_fbo
)
2037 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2038 return GL_COLOR_ATTACHMENT0
;
2040 TRACE("Returning GL_BACK\n");
2043 else if (surface
== swapchain
->front_buffer
)
2045 TRACE("Returning GL_FRONT\n");
2049 FIXME("Higher back buffer, returning GL_BACK\n");
2053 void surface_load(struct wined3d_surface
*surface
, BOOL srgb
)
2055 DWORD location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
2058 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
2060 if (surface
->resource
.pool
== WINED3D_POOL_SCRATCH
)
2061 ERR("Not supported on scratch surfaces.\n");
2063 ck_changed
= !(surface
->flags
& SFLAG_GLCKEY
) != !(surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
);
2065 /* Reload if either the texture and sysmem have different ideas about the
2066 * color key, or the actual key values changed. */
2067 if (ck_changed
|| ((surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
)
2068 && (surface
->gl_color_key
.color_space_low_value
2069 != surface
->container
->src_blt_color_key
.color_space_low_value
2070 || surface
->gl_color_key
.color_space_high_value
2071 != surface
->container
->src_blt_color_key
.color_space_high_value
)))
2073 TRACE("Reloading because of color keying\n");
2074 /* To perform the color key conversion we need a sysmem copy of
2075 * the surface. Make sure we have it. */
2077 surface_prepare_map_memory(surface
);
2078 surface_load_location(surface
, surface
->map_binding
);
2079 surface_invalidate_location(surface
, ~surface
->map_binding
);
2080 /* Switching color keying on / off may change the internal format. */
2082 surface_force_reload(surface
);
2084 else if (!(surface
->locations
& location
))
2086 TRACE("Reloading because surface is dirty.\n");
2090 TRACE("surface is already in texture\n");
2094 surface_load_location(surface
, location
);
2095 surface_evict_sysmem(surface
);
2098 /* See also float_16_to_32() in wined3d_private.h */
2099 static inline unsigned short float_32_to_16(const float *in
)
2102 float tmp
= fabsf(*in
);
2103 unsigned int mantissa
;
2106 /* Deal with special numbers */
2112 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
2114 if (tmp
< powf(2, 10))
2120 } while (tmp
< powf(2, 10));
2122 else if (tmp
>= powf(2, 11))
2128 } while (tmp
>= powf(2, 11));
2131 mantissa
= (unsigned int)tmp
;
2132 if (tmp
- mantissa
>= 0.5f
)
2133 ++mantissa
; /* Round to nearest, away from zero. */
2135 exp
+= 10; /* Normalize the mantissa. */
2136 exp
+= 15; /* Exponent is encoded with excess 15. */
2138 if (exp
> 30) /* too big */
2140 ret
= 0x7c00; /* INF */
2144 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2147 mantissa
= mantissa
>> 1;
2150 ret
= mantissa
& 0x3ff;
2154 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
2157 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
2161 ULONG CDECL
wined3d_surface_incref(struct wined3d_surface
*surface
)
2165 TRACE("surface %p, swapchain %p, container %p.\n",
2166 surface
, surface
->swapchain
, surface
->container
);
2168 if (surface
->swapchain
)
2169 return wined3d_swapchain_incref(surface
->swapchain
);
2171 if (surface
->container
)
2172 return wined3d_texture_incref(surface
->container
);
2174 refcount
= InterlockedIncrement(&surface
->resource
.ref
);
2175 TRACE("%p increasing refcount to %u.\n", surface
, refcount
);
2180 ULONG CDECL
wined3d_surface_decref(struct wined3d_surface
*surface
)
2184 TRACE("surface %p, swapchain %p, container %p.\n",
2185 surface
, surface
->swapchain
, surface
->container
);
2187 if (surface
->swapchain
)
2188 return wined3d_swapchain_decref(surface
->swapchain
);
2190 if (surface
->container
)
2191 return wined3d_texture_decref(surface
->container
);
2193 refcount
= InterlockedDecrement(&surface
->resource
.ref
);
2194 TRACE("%p decreasing refcount to %u.\n", surface
, refcount
);
2198 surface_cleanup(surface
);
2199 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
2201 TRACE("Destroyed surface %p.\n", surface
);
2202 HeapFree(GetProcessHeap(), 0, surface
);
2208 void CDECL
wined3d_surface_preload(struct wined3d_surface
*surface
)
2210 TRACE("surface %p.\n", surface
);
2212 if (!surface
->resource
.device
->d3d_initialized
)
2214 ERR("D3D not initialized.\n");
2218 wined3d_texture_preload(surface
->container
);
2221 void * CDECL
wined3d_surface_get_parent(const struct wined3d_surface
*surface
)
2223 TRACE("surface %p.\n", surface
);
2225 return surface
->resource
.parent
;
2228 struct wined3d_resource
* CDECL
wined3d_surface_get_resource(struct wined3d_surface
*surface
)
2230 TRACE("surface %p.\n", surface
);
2232 return &surface
->resource
;
2235 HRESULT CDECL
wined3d_surface_get_blt_status(const struct wined3d_surface
*surface
, DWORD flags
)
2237 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2241 case WINEDDGBS_CANBLT
:
2242 case WINEDDGBS_ISBLTDONE
:
2246 return WINED3DERR_INVALIDCALL
;
2250 HRESULT CDECL
wined3d_surface_get_flip_status(const struct wined3d_surface
*surface
, DWORD flags
)
2252 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2254 /* XXX: DDERR_INVALIDSURFACETYPE */
2258 case WINEDDGFS_CANFLIP
:
2259 case WINEDDGFS_ISFLIPDONE
:
2263 return WINED3DERR_INVALIDCALL
;
2267 HRESULT CDECL
wined3d_surface_is_lost(const struct wined3d_surface
*surface
)
2269 TRACE("surface %p.\n", surface
);
2271 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2272 return surface
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
2275 HRESULT CDECL
wined3d_surface_restore(struct wined3d_surface
*surface
)
2277 TRACE("surface %p.\n", surface
);
2279 surface
->flags
&= ~SFLAG_LOST
;
2283 DWORD CDECL
wined3d_surface_get_pitch(const struct wined3d_surface
*surface
)
2285 unsigned int alignment
;
2288 TRACE("surface %p.\n", surface
);
2291 return surface
->pitch
;
2293 alignment
= surface
->resource
.device
->surface_alignment
;
2294 pitch
= wined3d_format_calculate_pitch(surface
->resource
.format
, surface
->resource
.width
);
2295 pitch
= (pitch
+ alignment
- 1) & ~(alignment
- 1);
2297 TRACE("Returning %u.\n", pitch
);
2302 HRESULT CDECL
wined3d_surface_set_overlay_position(struct wined3d_surface
*surface
, LONG x
, LONG y
)
2306 TRACE("surface %p, x %d, y %d.\n", surface
, x
, y
);
2308 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2310 WARN("Not an overlay surface.\n");
2311 return WINEDDERR_NOTAOVERLAYSURFACE
;
2314 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
2315 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
2316 surface
->overlay_destrect
.left
= x
;
2317 surface
->overlay_destrect
.top
= y
;
2318 surface
->overlay_destrect
.right
= x
+ w
;
2319 surface
->overlay_destrect
.bottom
= y
+ h
;
2324 HRESULT CDECL
wined3d_surface_get_overlay_position(const struct wined3d_surface
*surface
, LONG
*x
, LONG
*y
)
2326 TRACE("surface %p, x %p, y %p.\n", surface
, x
, y
);
2328 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2330 TRACE("Not an overlay surface.\n");
2331 return WINEDDERR_NOTAOVERLAYSURFACE
;
2334 if (!surface
->overlay_dest
)
2336 TRACE("Overlay not visible.\n");
2339 return WINEDDERR_OVERLAYNOTVISIBLE
;
2342 *x
= surface
->overlay_destrect
.left
;
2343 *y
= surface
->overlay_destrect
.top
;
2345 TRACE("Returning position %d, %d.\n", *x
, *y
);
2350 HRESULT CDECL
wined3d_surface_update_overlay_z_order(struct wined3d_surface
*surface
,
2351 DWORD flags
, struct wined3d_surface
*ref
)
2353 FIXME("surface %p, flags %#x, ref %p stub!\n", surface
, flags
, ref
);
2355 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2357 TRACE("Not an overlay surface.\n");
2358 return WINEDDERR_NOTAOVERLAYSURFACE
;
2364 HRESULT CDECL
wined3d_surface_update_overlay(struct wined3d_surface
*surface
, const RECT
*src_rect
,
2365 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
, DWORD flags
, const WINEDDOVERLAYFX
*fx
)
2367 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2368 surface
, wine_dbgstr_rect(src_rect
), dst_surface
, wine_dbgstr_rect(dst_rect
), flags
, fx
);
2370 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2372 WARN("Not an overlay surface.\n");
2373 return WINEDDERR_NOTAOVERLAYSURFACE
;
2375 else if (!dst_surface
)
2377 WARN("Dest surface is NULL.\n");
2378 return WINED3DERR_INVALIDCALL
;
2383 surface
->overlay_srcrect
= *src_rect
;
2387 surface
->overlay_srcrect
.left
= 0;
2388 surface
->overlay_srcrect
.top
= 0;
2389 surface
->overlay_srcrect
.right
= surface
->resource
.width
;
2390 surface
->overlay_srcrect
.bottom
= surface
->resource
.height
;
2395 surface
->overlay_destrect
= *dst_rect
;
2399 surface
->overlay_destrect
.left
= 0;
2400 surface
->overlay_destrect
.top
= 0;
2401 surface
->overlay_destrect
.right
= dst_surface
? dst_surface
->resource
.width
: 0;
2402 surface
->overlay_destrect
.bottom
= dst_surface
? dst_surface
->resource
.height
: 0;
2405 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
2407 surface
->overlay_dest
= NULL
;
2408 list_remove(&surface
->overlay_entry
);
2411 if (flags
& WINEDDOVER_SHOW
)
2413 if (surface
->overlay_dest
!= dst_surface
)
2415 surface
->overlay_dest
= dst_surface
;
2416 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
2419 else if (flags
& WINEDDOVER_HIDE
)
2421 /* tests show that the rectangles are erased on hide */
2422 surface
->overlay_srcrect
.left
= 0; surface
->overlay_srcrect
.top
= 0;
2423 surface
->overlay_srcrect
.right
= 0; surface
->overlay_srcrect
.bottom
= 0;
2424 surface
->overlay_destrect
.left
= 0; surface
->overlay_destrect
.top
= 0;
2425 surface
->overlay_destrect
.right
= 0; surface
->overlay_destrect
.bottom
= 0;
2426 surface
->overlay_dest
= NULL
;
2432 HRESULT CDECL
wined3d_surface_update_desc(struct wined3d_surface
*surface
,
2433 UINT width
, UINT height
, enum wined3d_format_id format_id
,
2434 enum wined3d_multisample_type multisample_type
, UINT multisample_quality
,
2435 void *mem
, UINT pitch
)
2437 struct wined3d_device
*device
= surface
->resource
.device
;
2438 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
2439 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
2440 UINT resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, width
, height
, 1);
2441 BOOL create_dib
= FALSE
;
2443 DWORD valid_location
= 0;
2445 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u, "
2446 "mem %p, pitch %u.\n",
2447 surface
, width
, height
, debug_d3dformat(format_id
), multisample_type
, multisample_type
, mem
, pitch
);
2450 return WINED3DERR_INVALIDCALL
;
2452 if (surface
->resource
.map_count
|| (surface
->flags
& SFLAG_DCINUSE
))
2454 WARN("Surface is mapped or the DC is in use.\n");
2455 return WINED3DERR_INVALIDCALL
;
2458 if (device
->d3d_initialized
)
2459 surface
->resource
.resource_ops
->resource_unload(&surface
->resource
);
2461 if (surface
->flags
& SFLAG_DIBSECTION
)
2463 DeleteDC(surface
->hDC
);
2464 DeleteObject(surface
->dib
.DIBsection
);
2465 surface
->dib
.bitmap_data
= NULL
;
2466 surface
->flags
&= ~SFLAG_DIBSECTION
;
2470 surface
->locations
= 0;
2471 wined3d_resource_free_sysmem(&surface
->resource
);
2473 surface
->resource
.width
= width
;
2474 surface
->resource
.height
= height
;
2475 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
2476 || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
2478 surface
->pow2Width
= width
;
2479 surface
->pow2Height
= height
;
2483 surface
->pow2Width
= surface
->pow2Height
= 1;
2484 while (surface
->pow2Width
< width
)
2485 surface
->pow2Width
<<= 1;
2486 while (surface
->pow2Height
< height
)
2487 surface
->pow2Height
<<= 1;
2490 if (surface
->pow2Width
!= width
|| surface
->pow2Height
!= height
)
2491 surface
->flags
|= SFLAG_NONPOW2
;
2493 surface
->flags
&= ~SFLAG_NONPOW2
;
2495 surface
->user_memory
= mem
;
2496 if (surface
->user_memory
)
2498 surface
->map_binding
= WINED3D_LOCATION_USER_MEMORY
;
2499 valid_location
= WINED3D_LOCATION_USER_MEMORY
;
2501 surface
->pitch
= pitch
;
2502 surface
->resource
.format
= format
;
2503 surface
->resource
.multisample_type
= multisample_type
;
2504 surface
->resource
.multisample_quality
= multisample_quality
;
2506 surface
->resource
.size
= height
* surface
->pitch
;
2508 surface
->resource
.size
= resource_size
;
2510 /* The format might be changed to a format that needs conversion.
2511 * If the surface didn't use PBOs previously but could now, don't
2512 * change it - whatever made us not use PBOs might come back, e.g.
2514 if (surface
->map_binding
== WINED3D_LOCATION_BUFFER
&& !surface_use_pbo(surface
))
2515 surface
->map_binding
= create_dib
? WINED3D_LOCATION_DIB
: WINED3D_LOCATION_SYSMEM
;
2519 if (FAILED(hr
= surface_create_dib_section(surface
)))
2521 ERR("Failed to create dib section, hr %#x.\n", hr
);
2524 if (!valid_location
)
2525 valid_location
= WINED3D_LOCATION_DIB
;
2528 if (!valid_location
)
2530 surface_prepare_system_memory(surface
);
2531 valid_location
= WINED3D_LOCATION_SYSMEM
;
2534 surface_validate_location(surface
, valid_location
);
2539 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
2540 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2542 unsigned short *dst_s
;
2546 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2548 for (y
= 0; y
< h
; ++y
)
2550 src_f
= (const float *)(src
+ y
* pitch_in
);
2551 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
2552 for (x
= 0; x
< w
; ++x
)
2554 dst_s
[x
] = float_32_to_16(src_f
+ x
);
2559 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2560 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2562 static const unsigned char convert_5to8
[] =
2564 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
2565 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
2566 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
2567 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
2569 static const unsigned char convert_6to8
[] =
2571 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
2572 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
2573 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
2574 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
2575 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
2576 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
2577 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
2578 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
2582 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2584 for (y
= 0; y
< h
; ++y
)
2586 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
2587 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2588 for (x
= 0; x
< w
; ++x
)
2590 WORD pixel
= src_line
[x
];
2591 dst_line
[x
] = 0xff000000
2592 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
2593 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
2594 | convert_5to8
[(pixel
& 0x001f)];
2599 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
2600 * in both cases we're just setting the X / Alpha channel to 0xff. */
2601 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2602 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2606 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2608 for (y
= 0; y
< h
; ++y
)
2610 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
2611 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2613 for (x
= 0; x
< w
; ++x
)
2615 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
2620 static inline BYTE
cliptobyte(int x
)
2622 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
2625 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2626 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2628 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2631 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2633 for (y
= 0; y
< h
; ++y
)
2635 const BYTE
*src_line
= src
+ y
* pitch_in
;
2636 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2637 for (x
= 0; x
< w
; ++x
)
2639 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2640 * C = Y - 16; D = U - 128; E = V - 128;
2641 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2642 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2643 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2644 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2645 * U and V are shared between the pixels. */
2646 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2648 d
= (int) src_line
[1] - 128;
2649 e
= (int) src_line
[3] - 128;
2651 g2
= - 100 * d
- 208 * e
+ 128;
2654 c2
= 298 * ((int) src_line
[0] - 16);
2655 dst_line
[x
] = 0xff000000
2656 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
2657 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
2658 | cliptobyte((c2
+ b2
) >> 8); /* blue */
2659 /* Scale RGB values to 0..255 range,
2660 * then clip them if still not in range (may be negative),
2661 * then shift them within DWORD if necessary. */
2667 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
2668 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2671 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2673 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
2675 for (y
= 0; y
< h
; ++y
)
2677 const BYTE
*src_line
= src
+ y
* pitch_in
;
2678 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
2679 for (x
= 0; x
< w
; ++x
)
2681 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2682 * C = Y - 16; D = U - 128; E = V - 128;
2683 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2684 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2685 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2686 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2687 * U and V are shared between the pixels. */
2688 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2690 d
= (int) src_line
[1] - 128;
2691 e
= (int) src_line
[3] - 128;
2693 g2
= - 100 * d
- 208 * e
+ 128;
2696 c2
= 298 * ((int) src_line
[0] - 16);
2697 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
2698 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
2699 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
2700 /* Scale RGB values to 0..255 range,
2701 * then clip them if still not in range (may be negative),
2702 * then shift them within DWORD if necessary. */
2708 struct d3dfmt_converter_desc
2710 enum wined3d_format_id from
, to
;
2711 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
2714 static const struct d3dfmt_converter_desc converters
[] =
2716 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
2717 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
2718 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2719 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2720 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
2721 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
2724 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
2725 enum wined3d_format_id to
)
2729 for (i
= 0; i
< (sizeof(converters
) / sizeof(*converters
)); ++i
)
2731 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
2732 return &converters
[i
];
2738 static struct wined3d_texture
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
2740 struct wined3d_map_desc src_map
, dst_map
;
2741 const struct d3dfmt_converter_desc
*conv
;
2742 struct wined3d_texture
*ret
= NULL
;
2743 struct wined3d_resource_desc desc
;
2744 struct wined3d_surface
*dst
;
2746 conv
= find_converter(source
->resource
.format
->id
, to_fmt
);
2749 FIXME("Cannot find a conversion function from format %s to %s.\n",
2750 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
2754 /* FIXME: Multisampled conversion? */
2755 wined3d_resource_get_desc(&source
->resource
, &desc
);
2756 desc
.resource_type
= WINED3D_RTYPE_TEXTURE
;
2757 desc
.format
= to_fmt
;
2759 desc
.pool
= WINED3D_POOL_SCRATCH
;
2760 if (FAILED(wined3d_texture_create(source
->resource
.device
, &desc
, 1,
2761 WINED3D_SURFACE_MAPPABLE
| WINED3D_SURFACE_DISCARD
, NULL
, &wined3d_null_parent_ops
, &ret
)))
2763 ERR("Failed to create a destination surface for conversion.\n");
2766 dst
= surface_from_resource(wined3d_texture_get_sub_resource(ret
, 0));
2768 memset(&src_map
, 0, sizeof(src_map
));
2769 memset(&dst_map
, 0, sizeof(dst_map
));
2771 if (FAILED(wined3d_surface_map(source
, &src_map
, NULL
, WINED3D_MAP_READONLY
)))
2773 ERR("Failed to lock the source surface.\n");
2774 wined3d_texture_decref(ret
);
2777 if (FAILED(wined3d_surface_map(dst
, &dst_map
, NULL
, 0)))
2779 ERR("Failed to lock the destination surface.\n");
2780 wined3d_surface_unmap(source
);
2781 wined3d_texture_decref(ret
);
2785 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
,
2786 source
->resource
.width
, source
->resource
.height
);
2788 wined3d_surface_unmap(dst
);
2789 wined3d_surface_unmap(source
);
2794 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
2795 unsigned int bpp
, UINT pitch
, DWORD color
)
2802 #define COLORFILL_ROW(type) \
2804 type *d = (type *)buf; \
2805 for (x = 0; x < width; ++x) \
2806 d[x] = (type)color; \
2812 COLORFILL_ROW(BYTE
);
2816 COLORFILL_ROW(WORD
);
2822 for (x
= 0; x
< width
; ++x
, d
+= 3)
2824 d
[0] = (color
) & 0xff;
2825 d
[1] = (color
>> 8) & 0xff;
2826 d
[2] = (color
>> 16) & 0xff;
2831 COLORFILL_ROW(DWORD
);
2835 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
2836 return WINED3DERR_NOTAVAILABLE
;
2839 #undef COLORFILL_ROW
2841 /* Now copy first row. */
2843 for (y
= 1; y
< height
; ++y
)
2846 memcpy(buf
, first
, width
* bpp
);
2852 struct wined3d_surface
* CDECL
wined3d_surface_from_resource(struct wined3d_resource
*resource
)
2854 return surface_from_resource(resource
);
2857 HRESULT CDECL
wined3d_surface_unmap(struct wined3d_surface
*surface
)
2859 TRACE("surface %p.\n", surface
);
2861 if (!surface
->resource
.map_count
)
2863 WARN("Trying to unmap unmapped surface.\n");
2864 return WINEDDERR_NOTLOCKED
;
2866 --surface
->resource
.map_count
;
2868 surface
->surface_ops
->surface_unmap(surface
);
2873 HRESULT CDECL
wined3d_surface_map(struct wined3d_surface
*surface
,
2874 struct wined3d_map_desc
*map_desc
, const RECT
*rect
, DWORD flags
)
2876 const struct wined3d_format
*format
= surface
->resource
.format
;
2877 struct wined3d_device
*device
= surface
->resource
.device
;
2878 struct wined3d_context
*context
;
2879 const struct wined3d_gl_info
*gl_info
;
2882 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
2883 surface
, map_desc
, wine_dbgstr_rect(rect
), flags
);
2885 if (surface
->resource
.map_count
)
2887 WARN("Surface is already mapped.\n");
2888 return WINED3DERR_INVALIDCALL
;
2891 if ((format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && rect
2892 && !surface_check_block_align(surface
, rect
))
2894 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
2895 wine_dbgstr_rect(rect
), format
->block_width
, format
->block_height
);
2897 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
)
2898 return WINED3DERR_INVALIDCALL
;
2901 ++surface
->resource
.map_count
;
2903 if (!(surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
))
2904 WARN("Trying to lock unlockable surface.\n");
2906 /* Performance optimization: Count how often a surface is mapped, if it is
2907 * mapped regularly do not throw away the system memory copy. This avoids
2908 * the need to download the surface from OpenGL all the time. The surface
2909 * is still downloaded if the OpenGL texture is changed. */
2910 if (!(surface
->flags
& SFLAG_DYNLOCK
) && surface
->map_binding
== WINED3D_LOCATION_SYSMEM
)
2912 if (++surface
->lockCount
> MAXLOCKCOUNT
)
2914 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
2915 surface
->flags
|= SFLAG_DYNLOCK
;
2919 surface_prepare_map_memory(surface
);
2920 if (flags
& WINED3D_MAP_DISCARD
)
2922 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
2923 wined3d_debug_location(surface
->map_binding
));
2924 surface_validate_location(surface
, surface
->map_binding
);
2928 if (surface
->resource
.usage
& WINED3DUSAGE_DYNAMIC
)
2929 WARN_(d3d_perf
)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
2931 surface_load_location(surface
, surface
->map_binding
);
2934 if (!(flags
& (WINED3D_MAP_NO_DIRTY_UPDATE
| WINED3D_MAP_READONLY
)))
2935 surface_invalidate_location(surface
, ~surface
->map_binding
);
2937 switch (surface
->map_binding
)
2939 case WINED3D_LOCATION_SYSMEM
:
2940 base_memory
= surface
->resource
.heap_memory
;
2943 case WINED3D_LOCATION_USER_MEMORY
:
2944 base_memory
= surface
->user_memory
;
2947 case WINED3D_LOCATION_DIB
:
2948 base_memory
= surface
->dib
.bitmap_data
;
2951 case WINED3D_LOCATION_BUFFER
:
2952 context
= context_acquire(device
, NULL
);
2953 gl_info
= context
->gl_info
;
2955 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
2956 base_memory
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
2957 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
2958 checkGLcall("map PBO");
2960 context_release(context
);
2964 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->map_binding
));
2968 if (format
->flags
& WINED3DFMT_FLAG_BROKEN_PITCH
)
2969 map_desc
->row_pitch
= surface
->resource
.width
* format
->byte_count
;
2971 map_desc
->row_pitch
= wined3d_surface_get_pitch(surface
);
2972 map_desc
->slice_pitch
= 0;
2976 map_desc
->data
= base_memory
;
2977 surface
->lockedRect
.left
= 0;
2978 surface
->lockedRect
.top
= 0;
2979 surface
->lockedRect
.right
= surface
->resource
.width
;
2980 surface
->lockedRect
.bottom
= surface
->resource
.height
;
2984 if ((format
->flags
& (WINED3DFMT_FLAG_BLOCKS
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_BLOCKS
)
2986 /* Compressed textures are block based, so calculate the offset of
2987 * the block that contains the top-left pixel of the locked rectangle. */
2988 map_desc
->data
= base_memory
2989 + ((rect
->top
/ format
->block_height
) * map_desc
->row_pitch
)
2990 + ((rect
->left
/ format
->block_width
) * format
->block_byte_count
);
2994 map_desc
->data
= base_memory
2995 + (map_desc
->row_pitch
* rect
->top
)
2996 + (rect
->left
* format
->byte_count
);
2998 surface
->lockedRect
.left
= rect
->left
;
2999 surface
->lockedRect
.top
= rect
->top
;
3000 surface
->lockedRect
.right
= rect
->right
;
3001 surface
->lockedRect
.bottom
= rect
->bottom
;
3004 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
3005 TRACE("Returning memory %p, pitch %u.\n", map_desc
->data
, map_desc
->row_pitch
);
3010 HRESULT CDECL
wined3d_surface_getdc(struct wined3d_surface
*surface
, HDC
*dc
)
3014 TRACE("surface %p, dc %p.\n", surface
, dc
);
3016 /* Give more detailed info for ddraw. */
3017 if (surface
->flags
& SFLAG_DCINUSE
)
3018 return WINEDDERR_DCALREADYCREATED
;
3020 /* Can't GetDC if the surface is locked. */
3021 if (surface
->resource
.map_count
)
3022 return WINED3DERR_INVALIDCALL
;
3024 /* Create a DIB section if there isn't a dc yet. */
3027 if (surface
->flags
& SFLAG_CLIENT
)
3029 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
3030 surface_release_client_storage(surface
);
3032 hr
= surface_create_dib_section(surface
);
3034 return WINED3DERR_INVALIDCALL
;
3035 if (!(surface
->map_binding
== WINED3D_LOCATION_USER_MEMORY
3036 || surface
->flags
& SFLAG_PIN_SYSMEM
3038 surface
->map_binding
= WINED3D_LOCATION_DIB
;
3041 surface_load_location(surface
, WINED3D_LOCATION_DIB
);
3042 surface_invalidate_location(surface
, ~WINED3D_LOCATION_DIB
);
3044 surface
->flags
|= SFLAG_DCINUSE
;
3045 surface
->resource
.map_count
++;
3048 TRACE("Returning dc %p.\n", *dc
);
3053 HRESULT CDECL
wined3d_surface_releasedc(struct wined3d_surface
*surface
, HDC dc
)
3055 TRACE("surface %p, dc %p.\n", surface
, dc
);
3057 if (!(surface
->flags
& SFLAG_DCINUSE
))
3058 return WINEDDERR_NODC
;
3060 if (surface
->hDC
!= dc
)
3062 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
3064 return WINEDDERR_NODC
;
3067 surface
->resource
.map_count
--;
3068 surface
->flags
&= ~SFLAG_DCINUSE
;
3070 if (surface
->map_binding
== WINED3D_LOCATION_USER_MEMORY
|| (surface
->flags
& SFLAG_PIN_SYSMEM
3071 && surface
->map_binding
!= WINED3D_LOCATION_DIB
))
3073 /* The game Salammbo modifies the surface contents without mapping the surface between
3074 * a GetDC/ReleaseDC operation and flipping the surface. If the DIB remains the active
3075 * copy and is copied to the screen, this update, which draws the mouse pointer, is lost.
3076 * Do not only copy the DIB to the map location, but also make sure the map location is
3077 * copied back to the DIB in the next getdc call.
3079 * The same consideration applies to user memory surfaces. */
3080 surface_load_location(surface
, surface
->map_binding
);
3081 surface_invalidate_location(surface
, WINED3D_LOCATION_DIB
);
3087 static void read_from_framebuffer(struct wined3d_surface
*surface
, DWORD dst_location
)
3089 struct wined3d_device
*device
= surface
->resource
.device
;
3090 const struct wined3d_gl_info
*gl_info
;
3091 struct wined3d_context
*context
;
3093 BYTE
*row
, *top
, *bottom
;
3095 BOOL srcIsUpsideDown
;
3096 struct wined3d_bo_address data
;
3098 surface_get_memory(surface
, &data
, dst_location
);
3100 context
= context_acquire(device
, surface
);
3101 context_apply_blit_state(context
, device
);
3102 gl_info
= context
->gl_info
;
3104 /* Select the correct read buffer, and give some debug output.
3105 * There is no need to keep track of the current read buffer or reset it, every part of the code
3106 * that reads sets the read buffer as desired.
3108 if (surface_is_offscreen(surface
))
3110 /* Mapping the primary render target which is not on a swapchain.
3111 * Read from the back buffer. */
3112 TRACE("Mapping offscreen render target.\n");
3113 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3114 srcIsUpsideDown
= TRUE
;
3118 /* Onscreen surfaces are always part of a swapchain */
3119 GLenum buffer
= surface_get_gl_buffer(surface
);
3120 TRACE("Mapping %#x buffer.\n", buffer
);
3121 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
3122 checkGLcall("glReadBuffer");
3123 srcIsUpsideDown
= FALSE
;
3126 if (data
.buffer_object
)
3128 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
3129 checkGLcall("glBindBufferARB");
3132 /* Setup pixel store pack state -- to glReadPixels into the correct place */
3133 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, surface
->resource
.width
);
3134 checkGLcall("glPixelStorei");
3136 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0,
3137 surface
->resource
.width
, surface
->resource
.height
,
3138 surface
->resource
.format
->glFormat
,
3139 surface
->resource
.format
->glType
, data
.addr
);
3140 checkGLcall("glReadPixels");
3142 /* Reset previous pixel store pack state */
3143 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
3144 checkGLcall("glPixelStorei");
3146 if (!srcIsUpsideDown
)
3148 /* glReadPixels returns the image upside down, and there is no way to prevent this.
3149 * Flip the lines in software. */
3150 UINT pitch
= wined3d_surface_get_pitch(surface
);
3152 if (!(row
= HeapAlloc(GetProcessHeap(), 0, pitch
)))
3155 if (data
.buffer_object
)
3157 mem
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
3158 checkGLcall("glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB)");
3164 bottom
= mem
+ pitch
* (surface
->resource
.height
- 1);
3165 for (i
= 0; i
< surface
->resource
.height
/ 2; i
++)
3167 memcpy(row
, top
, pitch
);
3168 memcpy(top
, bottom
, pitch
);
3169 memcpy(bottom
, row
, pitch
);
3173 HeapFree(GetProcessHeap(), 0, row
);
3175 if (data
.buffer_object
)
3176 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB
));
3180 if (data
.buffer_object
)
3182 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
3183 checkGLcall("glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)");
3186 context_release(context
);
3189 /* Read the framebuffer contents into a texture. Note that this function
3190 * doesn't do any kind of flipping. Using this on an onscreen surface will
3191 * result in a flipped D3D texture. */
3192 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
)
3194 struct wined3d_device
*device
= surface
->resource
.device
;
3195 const struct wined3d_gl_info
*gl_info
;
3196 struct wined3d_context
*context
;
3198 context
= context_acquire(device
, surface
);
3199 gl_info
= context
->gl_info
;
3200 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
3202 surface_prepare_texture(surface
, context
, srgb
);
3203 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
3205 TRACE("Reading back offscreen render target %p.\n", surface
);
3207 if (surface_is_offscreen(surface
))
3208 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3210 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(surface
));
3211 checkGLcall("glReadBuffer");
3213 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
3214 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
3215 checkGLcall("glCopyTexSubImage2D");
3217 context_release(context
);
3220 /* Context activation is done by the caller. */
3221 static void surface_prepare_texture_internal(struct wined3d_surface
*surface
,
3222 struct wined3d_context
*context
, BOOL srgb
)
3224 DWORD alloc_flag
= srgb
? SFLAG_SRGBALLOCATED
: SFLAG_ALLOCATED
;
3225 enum wined3d_conversion_type convert
;
3226 struct wined3d_format format
;
3228 if (surface
->flags
& alloc_flag
) return;
3230 d3dfmt_get_conv(surface
, TRUE
, TRUE
, &format
, &convert
);
3231 if (convert
!= WINED3D_CT_NONE
|| format
.convert
)
3232 surface
->flags
|= SFLAG_CONVERTED
;
3233 else surface
->flags
&= ~SFLAG_CONVERTED
;
3235 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
3236 surface_allocate_surface(surface
, context
->gl_info
, &format
, srgb
);
3237 surface
->flags
|= alloc_flag
;
3240 /* Context activation is done by the caller. */
3241 void surface_prepare_texture(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
3243 struct wined3d_texture
*texture
= surface
->container
;
3244 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
3247 TRACE("surface %p is a subresource of texture %p.\n", surface
, texture
);
3249 for (i
= 0; i
< sub_count
; ++i
)
3251 struct wined3d_surface
*s
= surface_from_resource(texture
->sub_resources
[i
]);
3252 surface_prepare_texture_internal(s
, context
, srgb
);
3258 void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
3262 if (surface
->rb_multisample
)
3265 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
3266 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
3267 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, surface
->resource
.multisample_type
,
3268 surface
->resource
.format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
3269 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
3273 if (surface
->rb_resolved
)
3276 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
3277 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
3278 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, surface
->resource
.format
->glInternal
,
3279 surface
->pow2Width
, surface
->pow2Height
);
3280 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
3284 static BOOL
color_in_range(const struct wined3d_color_key
*color_key
, DWORD color
)
3286 /* FIXME: Is this really how color keys are supposed to work? I think it
3287 * makes more sense to compare the individual channels. */
3288 return color
>= color_key
->color_space_low_value
3289 && color
<= color_key
->color_space_high_value
;
3292 static HRESULT
d3dfmt_convert_surface(const BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
, UINT height
,
3293 UINT outpitch
, enum wined3d_conversion_type conversion_type
, struct wined3d_surface
*surface
)
3298 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
3299 src
, dst
, pitch
, width
, height
, outpitch
, conversion_type
, surface
);
3301 switch (conversion_type
)
3303 case WINED3D_CT_NONE
:
3305 memcpy(dst
, src
, pitch
* height
);
3309 case WINED3D_CT_PALETTED
:
3310 if (surface
->swapchain
&& surface
->swapchain
->palette
)
3313 const struct wined3d_palette
*palette
= surface
->swapchain
->palette
;
3314 for (y
= 0; y
< height
; y
++)
3316 source
= src
+ pitch
* y
;
3317 dest
= dst
+ outpitch
* y
;
3318 for (x
= 0; x
< width
; x
++)
3320 BYTE color
= *source
++;
3321 *dest
++ = palette
->colors
[color
].rgbRed
;
3322 *dest
++ = palette
->colors
[color
].rgbGreen
;
3323 *dest
++ = palette
->colors
[color
].rgbBlue
;
3330 /* This should probably use the system palette, but unless
3331 * the X server is running in P8 mode there is no such thing.
3332 * The probably best solution is to set the fixed 20 colors
3333 * from the default windows palette and set the rest to black,
3334 * white, or some ugly pink. For now use black for the entire
3335 * palette. Don't use pink everywhere. Age of Empires 2 draws
3336 * a front buffer filled with zeroes without a palette when
3337 * starting and we don't want the screen to flash in an ugly
3339 FIXME("P8 surface loaded without a palette.\n");
3340 memset(dst
, 0, height
* outpitch
);
3345 case WINED3D_CT_CK_565
:
3347 /* Converting the 565 format in 5551 packed to emulate color-keying.
3349 Note : in all these conversion, it would be best to average the averaging
3350 pixels to get the color of the pixel that will be color-keyed to
3351 prevent 'color bleeding'. This will be done later on if ever it is
3354 Note2: Nvidia documents say that their driver does not support alpha + color keying
3355 on the same surface and disables color keying in such a case
3361 TRACE("Color keyed 565\n");
3363 for (y
= 0; y
< height
; y
++) {
3364 Source
= (const WORD
*)(src
+ y
* pitch
);
3365 Dest
= (WORD
*) (dst
+ y
* outpitch
);
3366 for (x
= 0; x
< width
; x
++ ) {
3367 WORD color
= *Source
++;
3368 *Dest
= ((color
& 0xffc0) | ((color
& 0x1f) << 1));
3369 if (!color_in_range(&surface
->container
->src_blt_color_key
, color
))
3377 case WINED3D_CT_CK_5551
:
3379 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
3383 TRACE("Color keyed 5551\n");
3384 for (y
= 0; y
< height
; y
++) {
3385 Source
= (const WORD
*)(src
+ y
* pitch
);
3386 Dest
= (WORD
*) (dst
+ y
* outpitch
);
3387 for (x
= 0; x
< width
; x
++ ) {
3388 WORD color
= *Source
++;
3390 if (!color_in_range(&surface
->container
->src_blt_color_key
, color
))
3393 *Dest
&= ~(1 << 15);
3400 case WINED3D_CT_CK_RGB24
:
3402 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
3404 for (y
= 0; y
< height
; y
++)
3406 source
= src
+ pitch
* y
;
3407 dest
= dst
+ outpitch
* y
;
3408 for (x
= 0; x
< width
; x
++) {
3409 DWORD color
= ((DWORD
)source
[0] << 16) + ((DWORD
)source
[1] << 8) + (DWORD
)source
[2] ;
3410 DWORD dstcolor
= color
<< 8;
3411 if (!color_in_range(&surface
->container
->src_blt_color_key
, color
))
3413 *(DWORD
*)dest
= dstcolor
;
3421 case WINED3D_CT_RGB32_888
:
3423 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
3425 for (y
= 0; y
< height
; y
++)
3427 source
= src
+ pitch
* y
;
3428 dest
= dst
+ outpitch
* y
;
3429 for (x
= 0; x
< width
; x
++) {
3430 DWORD color
= 0xffffff & *(const DWORD
*)source
;
3431 DWORD dstcolor
= color
<< 8;
3432 if (!color_in_range(&surface
->container
->src_blt_color_key
, color
))
3434 *(DWORD
*)dest
= dstcolor
;
3442 case WINED3D_CT_CK_ARGB32
:
3445 for (y
= 0; y
< height
; ++y
)
3447 source
= src
+ pitch
* y
;
3448 dest
= dst
+ outpitch
* y
;
3449 for (x
= 0; x
< width
; ++x
)
3451 DWORD color
= *(const DWORD
*)source
;
3452 if (color_in_range(&surface
->container
->src_blt_color_key
, color
))
3453 color
&= ~0xff000000;
3454 *(DWORD
*)dest
= color
;
3463 ERR("Unsupported conversion type %#x.\n", conversion_type
);
3468 void flip_surface(struct wined3d_surface
*front
, struct wined3d_surface
*back
)
3470 if (front
->container
->level_count
!= 1 || front
->container
->layer_count
!= 1
3471 || back
->container
->level_count
!= 1 || back
->container
->layer_count
!= 1)
3472 ERR("Flip between surfaces %p and %p not supported.\n", front
, back
);
3474 /* Flip the surface contents */
3479 front
->hDC
= back
->hDC
;
3483 /* Flip the DIBsection */
3485 HBITMAP tmp
= front
->dib
.DIBsection
;
3486 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
3487 back
->dib
.DIBsection
= tmp
;
3490 /* Flip the surface data */
3494 tmp
= front
->dib
.bitmap_data
;
3495 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
3496 back
->dib
.bitmap_data
= tmp
;
3498 tmp
= front
->resource
.heap_memory
;
3499 front
->resource
.heap_memory
= back
->resource
.heap_memory
;
3500 back
->resource
.heap_memory
= tmp
;
3505 GLuint tmp_pbo
= front
->pbo
;
3506 front
->pbo
= back
->pbo
;
3507 back
->pbo
= tmp_pbo
;
3510 /* Flip the opengl texture */
3514 tmp
= back
->container
->texture_rgb
.name
;
3515 back
->container
->texture_rgb
.name
= front
->container
->texture_rgb
.name
;
3516 front
->container
->texture_rgb
.name
= tmp
;
3518 tmp
= back
->container
->texture_srgb
.name
;
3519 back
->container
->texture_srgb
.name
= front
->container
->texture_srgb
.name
;
3520 front
->container
->texture_srgb
.name
= tmp
;
3522 tmp
= back
->rb_multisample
;
3523 back
->rb_multisample
= front
->rb_multisample
;
3524 front
->rb_multisample
= tmp
;
3526 tmp
= back
->rb_resolved
;
3527 back
->rb_resolved
= front
->rb_resolved
;
3528 front
->rb_resolved
= tmp
;
3530 resource_unload(&back
->resource
);
3531 resource_unload(&front
->resource
);
3535 DWORD tmp_flags
= back
->flags
;
3536 back
->flags
= front
->flags
;
3537 front
->flags
= tmp_flags
;
3539 tmp_flags
= back
->locations
;
3540 back
->locations
= front
->locations
;
3541 front
->locations
= tmp_flags
;
3545 /* Does a direct frame buffer -> texture copy. Stretching is done with single
3546 * pixel copy calls. */
3547 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3548 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3550 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3551 const struct wined3d_gl_info
*gl_info
;
3553 struct wined3d_context
*context
;
3554 BOOL upsidedown
= FALSE
;
3555 RECT dst_rect
= *dst_rect_in
;
3557 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3558 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3560 if(dst_rect
.top
> dst_rect
.bottom
) {
3561 UINT tmp
= dst_rect
.bottom
;
3562 dst_rect
.bottom
= dst_rect
.top
;
3567 context
= context_acquire(device
, src_surface
);
3568 gl_info
= context
->gl_info
;
3569 context_apply_blit_state(context
, device
);
3570 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3572 /* Bind the target texture */
3573 context_bind_texture(context
, dst_surface
->container
->target
, dst_surface
->container
->texture_rgb
.name
);
3574 if (surface_is_offscreen(src_surface
))
3576 TRACE("Reading from an offscreen target\n");
3577 upsidedown
= !upsidedown
;
3578 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3582 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3584 checkGLcall("glReadBuffer");
3586 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
3587 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
3589 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3591 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3593 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3594 ERR("Texture filtering not supported in direct blit.\n");
3596 else if ((filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3597 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3599 ERR("Texture filtering not supported in direct blit\n");
3603 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3604 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3606 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
3607 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3608 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
3609 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
3610 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3615 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
3616 /* I have to process this row by row to swap the image,
3617 * otherwise it would be upside down, so stretching in y direction
3618 * doesn't cost extra time
3620 * However, stretching in x direction can be avoided if not necessary
3622 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
3623 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3625 /* Well, that stuff works, but it's very slow.
3626 * find a better way instead
3630 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
3632 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3633 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
3634 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
3639 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3640 dst_rect
.left
/* x offset */, row
/* y offset */,
3641 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
3645 checkGLcall("glCopyTexSubImage2D");
3647 context_release(context
);
3649 /* The texture is now most up to date - If the surface is a render target
3650 * and has a drawable, this path is never entered. */
3651 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3652 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3655 /* Uses the hardware to stretch and flip the image */
3656 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3657 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3659 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3660 GLuint src
, backup
= 0;
3661 float left
, right
, top
, bottom
; /* Texture coordinates */
3662 UINT fbwidth
= src_surface
->resource
.width
;
3663 UINT fbheight
= src_surface
->resource
.height
;
3664 const struct wined3d_gl_info
*gl_info
;
3665 struct wined3d_context
*context
;
3666 GLenum drawBuffer
= GL_BACK
;
3667 GLenum texture_target
;
3668 BOOL noBackBufferBackup
;
3670 BOOL upsidedown
= FALSE
;
3671 RECT dst_rect
= *dst_rect_in
;
3673 TRACE("Using hwstretch blit\n");
3674 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3675 context
= context_acquire(device
, src_surface
);
3676 gl_info
= context
->gl_info
;
3677 context_apply_blit_state(context
, device
);
3678 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3680 src_offscreen
= surface_is_offscreen(src_surface
);
3681 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
3682 if (!noBackBufferBackup
&& !src_surface
->container
->texture_rgb
.name
)
3684 /* Get it a description */
3685 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3688 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3689 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3691 if (context
->aux_buffers
>= 2)
3693 /* Got more than one aux buffer? Use the 2nd aux buffer */
3694 drawBuffer
= GL_AUX1
;
3696 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
3698 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3699 drawBuffer
= GL_AUX0
;
3702 if (noBackBufferBackup
)
3704 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &backup
);
3705 checkGLcall("glGenTextures");
3706 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3707 texture_target
= GL_TEXTURE_2D
;
3711 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3712 * we are reading from the back buffer, the backup can be used as source texture
3714 texture_target
= src_surface
->texture_target
;
3715 context_bind_texture(context
, texture_target
, src_surface
->container
->texture_rgb
.name
);
3716 gl_info
->gl_ops
.gl
.p_glEnable(texture_target
);
3717 checkGLcall("glEnable(texture_target)");
3719 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3720 src_surface
->locations
&= ~WINED3D_LOCATION_TEXTURE_RGB
;
3723 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3724 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3726 if(dst_rect
.top
> dst_rect
.bottom
) {
3727 UINT tmp
= dst_rect
.bottom
;
3728 dst_rect
.bottom
= dst_rect
.top
;
3735 TRACE("Reading from an offscreen target\n");
3736 upsidedown
= !upsidedown
;
3737 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3741 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3744 /* TODO: Only back up the part that will be overwritten */
3745 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3747 checkGLcall("glCopyTexSubImage2D");
3749 /* No issue with overriding these - the sampler is dirty due to blit usage */
3750 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
,
3751 wined3d_gl_mag_filter(magLookup
, filter
));
3752 checkGLcall("glTexParameteri");
3753 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
3754 wined3d_gl_min_mip_filter(minMipLookup
, filter
, WINED3D_TEXF_NONE
));
3755 checkGLcall("glTexParameteri");
3757 if (!src_surface
->swapchain
|| src_surface
== src_surface
->swapchain
->back_buffers
[0])
3759 src
= backup
? backup
: src_surface
->container
->texture_rgb
.name
;
3763 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_FRONT
);
3764 checkGLcall("glReadBuffer(GL_FRONT)");
3766 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &src
);
3767 checkGLcall("glGenTextures(1, &src)");
3768 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
3770 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3771 * out for power of 2 sizes
3773 gl_info
->gl_ops
.gl
.p_glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
3774 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
3775 checkGLcall("glTexImage2D");
3776 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3778 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
3779 checkGLcall("glTexParameteri");
3780 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
3781 checkGLcall("glTexParameteri");
3783 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_BACK
);
3784 checkGLcall("glReadBuffer(GL_BACK)");
3786 if (texture_target
!= GL_TEXTURE_2D
)
3788 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3789 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3790 texture_target
= GL_TEXTURE_2D
;
3793 checkGLcall("glEnd and previous");
3795 left
= src_rect
->left
;
3796 right
= src_rect
->right
;
3800 top
= src_surface
->resource
.height
- src_rect
->top
;
3801 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
3805 top
= src_surface
->resource
.height
- src_rect
->bottom
;
3806 bottom
= src_surface
->resource
.height
- src_rect
->top
;
3809 if (src_surface
->flags
& SFLAG_NORMCOORD
)
3811 left
/= src_surface
->pow2Width
;
3812 right
/= src_surface
->pow2Width
;
3813 top
/= src_surface
->pow2Height
;
3814 bottom
/= src_surface
->pow2Height
;
3817 /* draw the source texture stretched and upside down. The correct surface is bound already */
3818 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
3819 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
3821 context_set_draw_buffer(context
, drawBuffer
);
3822 gl_info
->gl_ops
.gl
.p_glReadBuffer(drawBuffer
);
3824 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3826 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, bottom
);
3827 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3830 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, top
);
3831 gl_info
->gl_ops
.gl
.p_glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
3834 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, top
);
3835 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3838 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, bottom
);
3839 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
3840 gl_info
->gl_ops
.gl
.p_glEnd();
3841 checkGLcall("glEnd and previous");
3843 if (texture_target
!= dst_surface
->texture_target
)
3845 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3846 gl_info
->gl_ops
.gl
.p_glEnable(dst_surface
->texture_target
);
3847 texture_target
= dst_surface
->texture_target
;
3850 /* Now read the stretched and upside down image into the destination texture */
3851 context_bind_texture(context
, texture_target
, dst_surface
->container
->texture_rgb
.name
);
3852 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
,
3854 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
3855 0, 0, /* We blitted the image to the origin */
3856 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3857 checkGLcall("glCopyTexSubImage2D");
3859 if (drawBuffer
== GL_BACK
)
3861 /* Write the back buffer backup back. */
3864 if (texture_target
!= GL_TEXTURE_2D
)
3866 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3867 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3868 texture_target
= GL_TEXTURE_2D
;
3870 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3874 if (texture_target
!= src_surface
->texture_target
)
3876 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3877 gl_info
->gl_ops
.gl
.p_glEnable(src_surface
->texture_target
);
3878 texture_target
= src_surface
->texture_target
;
3880 context_bind_texture(context
, src_surface
->texture_target
, src_surface
->container
->texture_rgb
.name
);
3883 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3885 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, 0.0f
);
3886 gl_info
->gl_ops
.gl
.p_glVertex2i(0, fbheight
);
3889 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
3890 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3893 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
3894 (float)fbheight
/ (float)src_surface
->pow2Height
);
3895 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, 0);
3898 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
3899 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, fbheight
);
3900 gl_info
->gl_ops
.gl
.p_glEnd();
3902 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3903 checkGLcall("glDisable(texture_target)");
3906 if (src
!= src_surface
->container
->texture_rgb
.name
&& src
!= backup
)
3908 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &src
);
3909 checkGLcall("glDeleteTextures(1, &src)");
3913 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &backup
);
3914 checkGLcall("glDeleteTextures(1, &backup)");
3917 if (wined3d_settings
.strict_draw_ordering
)
3918 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3920 context_release(context
);
3922 /* The texture is now most up to date - If the surface is a render target
3923 * and has a drawable, this path is never entered. */
3924 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3925 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3928 /* Front buffer coordinates are always full screen coordinates, but our GL
3929 * drawable is limited to the window's client area. The sysmem and texture
3930 * copies do have the full screen size. Note that GL has a bottom-left
3931 * origin, while D3D has a top-left origin. */
3932 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
3934 UINT drawable_height
;
3936 if (surface
->swapchain
&& surface
== surface
->swapchain
->front_buffer
)
3938 POINT offset
= {0, 0};
3941 ScreenToClient(window
, &offset
);
3942 OffsetRect(rect
, offset
.x
, offset
.y
);
3944 GetClientRect(window
, &windowsize
);
3945 drawable_height
= windowsize
.bottom
- windowsize
.top
;
3949 drawable_height
= surface
->resource
.height
;
3952 rect
->top
= drawable_height
- rect
->top
;
3953 rect
->bottom
= drawable_height
- rect
->bottom
;
3956 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
3957 enum wined3d_texture_filter_type filter
, BOOL alpha_test
,
3958 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
3959 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
3961 const struct wined3d_gl_info
*gl_info
;
3962 struct wined3d_context
*context
;
3963 RECT src_rect
, dst_rect
;
3965 src_rect
= *src_rect_in
;
3966 dst_rect
= *dst_rect_in
;
3968 context
= context_acquire(device
, dst_surface
);
3969 gl_info
= context
->gl_info
;
3971 /* Make sure the surface is up-to-date. This should probably use
3972 * surface_load_location() and worry about the destination surface too,
3973 * unless we're overwriting it completely. */
3974 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3976 /* Activate the destination context, set it up for blitting */
3977 context_apply_blit_state(context
, device
);
3979 if (!surface_is_offscreen(dst_surface
))
3980 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
3982 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
);
3986 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
3987 checkGLcall("glEnable(GL_ALPHA_TEST)");
3989 /* For P8 surfaces, the alpha component contains the palette index.
3990 * Which means that the colorkey is one of the palette entries. In
3991 * other cases pixels that should be masked away have alpha set to 0. */
3992 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3993 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
,
3994 (float)src_surface
->container
->src_blt_color_key
.color_space_low_value
/ 256.0f
);
3996 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
3997 checkGLcall("glAlphaFunc");
4001 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
4002 checkGLcall("glDisable(GL_ALPHA_TEST)");
4005 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
4009 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
4010 checkGLcall("glDisable(GL_ALPHA_TEST)");
4013 /* Leave the opengl state valid for blitting */
4014 device
->blitter
->unset_shader(context
->gl_info
);
4016 if (wined3d_settings
.strict_draw_ordering
4017 || (dst_surface
->swapchain
&& dst_surface
->swapchain
->front_buffer
== dst_surface
))
4018 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4020 context_release(context
);
4023 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
4025 struct wined3d_device
*device
= s
->resource
.device
;
4026 const struct blit_shader
*blitter
;
4028 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_FILL
,
4029 NULL
, 0, 0, NULL
, rect
, s
->resource
.usage
, s
->resource
.pool
, s
->resource
.format
);
4032 FIXME("No blitter is capable of performing the requested color fill operation.\n");
4033 return WINED3DERR_INVALIDCALL
;
4036 return blitter
->color_fill(device
, s
, rect
, color
);
4039 static HRESULT
surface_blt_special(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
4040 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
,
4041 enum wined3d_texture_filter_type filter
)
4043 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4044 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4045 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
4047 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
4048 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
4049 flags
, DDBltFx
, debug_d3dtexturefiltertype(filter
));
4051 /* Get the swapchain. One of the surfaces has to be a primary surface */
4052 if (dst_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
4054 WARN("Destination is in sysmem, rejecting gl blt\n");
4055 return WINED3DERR_INVALIDCALL
;
4058 dst_swapchain
= dst_surface
->swapchain
;
4062 if (src_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
4064 WARN("Src is in sysmem, rejecting gl blt\n");
4065 return WINED3DERR_INVALIDCALL
;
4068 src_swapchain
= src_surface
->swapchain
;
4072 src_swapchain
= NULL
;
4075 /* Early sort out of cases where no render target is used */
4076 if (!dst_swapchain
&& !src_swapchain
4077 && src_surface
!= device
->fb
.render_targets
[0]
4078 && dst_surface
!= device
->fb
.render_targets
[0])
4080 TRACE("No surface is render target, not using hardware blit.\n");
4081 return WINED3DERR_INVALIDCALL
;
4084 /* No destination color keying supported */
4085 if (flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
))
4087 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
4088 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
4089 return WINED3DERR_INVALIDCALL
;
4092 if (dst_swapchain
&& dst_swapchain
== src_swapchain
)
4094 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
4095 return WINED3DERR_INVALIDCALL
;
4098 if (dst_swapchain
&& src_swapchain
)
4100 FIXME("Implement hardware blit between two different swapchains\n");
4101 return WINED3DERR_INVALIDCALL
;
4106 /* Handled with regular texture -> swapchain blit */
4107 if (src_surface
== device
->fb
.render_targets
[0])
4108 TRACE("Blit from active render target to a swapchain\n");
4110 else if (src_swapchain
&& dst_surface
== device
->fb
.render_targets
[0])
4112 FIXME("Implement blit from a swapchain to the active render target\n");
4113 return WINED3DERR_INVALIDCALL
;
4116 if ((src_swapchain
|| src_surface
== device
->fb
.render_targets
[0]) && !dst_swapchain
)
4118 /* Blit from render target to texture */
4121 /* P8 read back is not implemented */
4122 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
4123 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
4125 TRACE("P8 read back not supported by frame buffer to texture blit\n");
4126 return WINED3DERR_INVALIDCALL
;
4129 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
4131 TRACE("Color keying not supported by frame buffer to texture blit\n");
4132 return WINED3DERR_INVALIDCALL
;
4133 /* Destination color key is checked above */
4136 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
4141 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
4142 * flip the image nor scale it.
4144 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
4145 * -> If the app wants an image width an unscaled width, copy it line per line
4146 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
4147 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
4148 * back buffer. This is slower than reading line per line, thus not used for flipping
4149 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
4150 * pixel by pixel. */
4151 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
4152 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
4154 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
4155 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
4159 TRACE("Using hardware stretching to flip / stretch the texture.\n");
4160 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
4163 surface_evict_sysmem(dst_surface
);
4167 else if (src_surface
)
4169 /* Blit from offscreen surface to render target */
4170 struct wined3d_color_key old_blt_key
= src_surface
->container
->src_blt_color_key
;
4171 DWORD old_color_key_flags
= src_surface
->container
->color_key_flags
;
4173 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
4175 if (!device
->blitter
->blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4176 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
4177 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
4179 FIXME("Unsupported blit operation falling back to software\n");
4180 return WINED3DERR_INVALIDCALL
;
4183 /* Color keying: Check if we have to do a color keyed blt,
4184 * and if not check if a color key is activated.
4186 * Just modify the color keying parameters in the surface and restore them afterwards
4187 * The surface keeps track of the color key last used to load the opengl surface.
4188 * PreLoad will catch the change to the flags and color key and reload if necessary.
4190 if (flags
& WINEDDBLT_KEYSRC
)
4192 /* Use color key from surface */
4194 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
4196 /* Use color key from DDBltFx */
4197 src_surface
->container
->color_key_flags
|= WINEDDSD_CKSRCBLT
;
4198 src_surface
->container
->src_blt_color_key
= DDBltFx
->ddckSrcColorkey
;
4202 /* Do not use color key */
4203 src_surface
->container
->color_key_flags
&= ~WINEDDSD_CKSRCBLT
;
4206 surface_blt_to_drawable(device
, filter
,
4207 flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_ALPHATEST
),
4208 src_surface
, src_rect
, dst_surface
, dst_rect
);
4210 /* Restore the color key parameters */
4211 src_surface
->container
->color_key_flags
= old_color_key_flags
;
4212 src_surface
->container
->src_blt_color_key
= old_blt_key
;
4214 surface_validate_location(dst_surface
, dst_surface
->draw_binding
);
4215 surface_invalidate_location(dst_surface
, ~dst_surface
->draw_binding
);
4220 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
4221 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
4222 return WINED3DERR_INVALIDCALL
;
4225 /* Context activation is done by the caller. */
4226 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
4227 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
4229 struct wined3d_device
*device
= surface
->resource
.device
;
4230 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4231 GLint compare_mode
= GL_NONE
;
4232 struct blt_info info
;
4233 GLint old_binding
= 0;
4236 gl_info
->gl_ops
.gl
.p_glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
4238 gl_info
->gl_ops
.gl
.p_glDisable(GL_CULL_FACE
);
4239 gl_info
->gl_ops
.gl
.p_glDisable(GL_BLEND
);
4240 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
4241 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
4242 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST
);
4243 gl_info
->gl_ops
.gl
.p_glEnable(GL_DEPTH_TEST
);
4244 gl_info
->gl_ops
.gl
.p_glDepthFunc(GL_ALWAYS
);
4245 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
4246 gl_info
->gl_ops
.gl
.p_glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
4247 gl_info
->gl_ops
.gl
.p_glViewport(x
, y
, w
, h
);
4248 gl_info
->gl_ops
.gl
.p_glDepthRange(0.0, 1.0);
4250 SetRect(&rect
, 0, h
, w
, 0);
4251 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
4252 context_active_texture(context
, context
->gl_info
, 0);
4253 gl_info
->gl_ops
.gl
.p_glGetIntegerv(info
.binding
, &old_binding
);
4254 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, texture
);
4255 if (gl_info
->supported
[ARB_SHADOW
])
4257 gl_info
->gl_ops
.gl
.p_glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
4258 if (compare_mode
!= GL_NONE
)
4259 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
4262 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
4263 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
4265 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
4266 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
4267 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, -1.0f
);
4268 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
4269 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, -1.0f
);
4270 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
4271 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, 1.0f
);
4272 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
4273 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, 1.0f
);
4274 gl_info
->gl_ops
.gl
.p_glEnd();
4276 if (compare_mode
!= GL_NONE
)
4277 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
4278 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, old_binding
);
4280 gl_info
->gl_ops
.gl
.p_glPopAttrib();
4282 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
4285 void surface_modify_ds_location(struct wined3d_surface
*surface
,
4286 DWORD location
, UINT w
, UINT h
)
4288 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
4290 if (((surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && !(location
& WINED3D_LOCATION_TEXTURE_RGB
))
4291 || (!(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && (location
& WINED3D_LOCATION_TEXTURE_RGB
)))
4292 wined3d_texture_set_dirty(surface
->container
);
4294 surface
->ds_current_size
.cx
= w
;
4295 surface
->ds_current_size
.cy
= h
;
4296 surface
->locations
= location
;
4299 /* Context activation is done by the caller. */
4300 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
4302 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4303 struct wined3d_device
*device
= surface
->resource
.device
;
4306 TRACE("surface %p, new location %#x.\n", surface
, location
);
4308 /* TODO: Make this work for modes other than FBO */
4309 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
4311 if (!(surface
->locations
& location
))
4313 w
= surface
->ds_current_size
.cx
;
4314 h
= surface
->ds_current_size
.cy
;
4315 surface
->ds_current_size
.cx
= 0;
4316 surface
->ds_current_size
.cy
= 0;
4320 w
= surface
->resource
.width
;
4321 h
= surface
->resource
.height
;
4324 if (surface
->ds_current_size
.cx
== surface
->resource
.width
4325 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
4327 TRACE("Location (%#x) is already up to date.\n", location
);
4331 if (surface
->current_renderbuffer
)
4333 FIXME("Not supported with fixed up depth stencil.\n");
4337 if (surface
->locations
& WINED3D_LOCATION_DISCARDED
)
4339 TRACE("Surface was discarded, no need copy data.\n");
4342 case WINED3D_LOCATION_TEXTURE_RGB
:
4343 surface_prepare_texture(surface
, context
, FALSE
);
4345 case WINED3D_LOCATION_RB_MULTISAMPLE
:
4346 surface_prepare_rb(surface
, gl_info
, TRUE
);
4348 case WINED3D_LOCATION_DRAWABLE
:
4352 FIXME("Unhandled location %#x\n", location
);
4354 surface
->locations
&= ~WINED3D_LOCATION_DISCARDED
;
4355 surface
->locations
|= location
;
4356 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4357 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4361 if (!surface
->locations
)
4363 FIXME("No up to date depth stencil location.\n");
4364 surface
->locations
|= location
;
4365 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4366 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4370 if (location
== WINED3D_LOCATION_TEXTURE_RGB
)
4372 GLint old_binding
= 0;
4375 /* The render target is allowed to be smaller than the depth/stencil
4376 * buffer, so the onscreen depth/stencil buffer is potentially smaller
4377 * than the offscreen surface. Don't overwrite the offscreen surface
4378 * with undefined data. */
4379 w
= min(w
, context
->swapchain
->desc
.backbuffer_width
);
4380 h
= min(h
, context
->swapchain
->desc
.backbuffer_height
);
4382 TRACE("Copying onscreen depth buffer to depth texture.\n");
4384 if (!device
->depth_blt_texture
)
4385 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &device
->depth_blt_texture
);
4387 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4388 * directly on the FBO texture. That's because we need to flip. */
4389 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4390 context
->swapchain
->front_buffer
, NULL
, WINED3D_LOCATION_DRAWABLE
);
4391 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
4393 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
4394 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
4398 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
4399 bind_target
= GL_TEXTURE_2D
;
4401 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, device
->depth_blt_texture
);
4402 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
4403 * internal format, because the internal format might include stencil
4404 * data. In principle we should copy stencil data as well, but unless
4405 * the driver supports stencil export it's hard to do, and doesn't
4406 * seem to be needed in practice. If the hardware doesn't support
4407 * writing stencil data, the glCopyTexImage2D() call might trigger
4408 * software fallbacks. */
4409 gl_info
->gl_ops
.gl
.p_glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
4410 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
4411 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
4412 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
4413 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
4414 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
4415 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
4416 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, old_binding
);
4418 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4419 NULL
, surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4420 context_set_draw_buffer(context
, GL_NONE
);
4422 /* Do the actual blit */
4423 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
4424 checkGLcall("depth_blt");
4426 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
4428 if (wined3d_settings
.strict_draw_ordering
)
4429 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4431 else if (location
== WINED3D_LOCATION_DRAWABLE
)
4433 TRACE("Copying depth texture to onscreen depth buffer.\n");
4435 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4436 context
->swapchain
->front_buffer
, NULL
, WINED3D_LOCATION_DRAWABLE
);
4437 surface_depth_blt(surface
, context
, surface
->container
->texture_rgb
.name
,
4438 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
4439 checkGLcall("depth_blt");
4441 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
4443 if (wined3d_settings
.strict_draw_ordering
)
4444 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4448 ERR("Invalid location (%#x) specified.\n", location
);
4451 surface
->locations
|= location
;
4452 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4453 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4456 void surface_validate_location(struct wined3d_surface
*surface
, DWORD location
)
4458 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4460 surface
->locations
|= location
;
4463 void surface_invalidate_location(struct wined3d_surface
*surface
, DWORD location
)
4465 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4467 if (location
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4468 wined3d_texture_set_dirty(surface
->container
);
4469 surface
->locations
&= ~location
;
4471 if (!surface
->locations
)
4472 ERR("Surface %p does not have any up to date location.\n", surface
);
4475 static DWORD
resource_access_from_location(DWORD location
)
4479 case WINED3D_LOCATION_SYSMEM
:
4480 case WINED3D_LOCATION_USER_MEMORY
:
4481 case WINED3D_LOCATION_DIB
:
4482 case WINED3D_LOCATION_BUFFER
:
4483 return WINED3D_RESOURCE_ACCESS_CPU
;
4485 case WINED3D_LOCATION_DRAWABLE
:
4486 case WINED3D_LOCATION_TEXTURE_SRGB
:
4487 case WINED3D_LOCATION_TEXTURE_RGB
:
4488 case WINED3D_LOCATION_RB_MULTISAMPLE
:
4489 case WINED3D_LOCATION_RB_RESOLVED
:
4490 return WINED3D_RESOURCE_ACCESS_GPU
;
4493 FIXME("Unhandled location %#x.\n", location
);
4498 static void surface_copy_simple_location(struct wined3d_surface
*surface
, DWORD location
)
4500 struct wined3d_device
*device
= surface
->resource
.device
;
4501 struct wined3d_context
*context
;
4502 const struct wined3d_gl_info
*gl_info
;
4503 struct wined3d_bo_address dst
, src
;
4504 UINT size
= surface
->resource
.size
;
4506 surface_get_memory(surface
, &dst
, location
);
4507 surface_get_memory(surface
, &src
, surface
->locations
);
4509 if (dst
.buffer_object
)
4511 context
= context_acquire(device
, NULL
);
4512 gl_info
= context
->gl_info
;
4513 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, dst
.buffer_object
));
4514 GL_EXTCALL(glBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0, size
, src
.addr
));
4515 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4516 checkGLcall("Upload PBO");
4517 context_release(context
);
4520 if (src
.buffer_object
)
4522 context
= context_acquire(device
, NULL
);
4523 gl_info
= context
->gl_info
;
4524 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, src
.buffer_object
));
4525 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_PACK_BUFFER_ARB
, 0, size
, dst
.addr
));
4526 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
4527 checkGLcall("Download PBO");
4528 context_release(context
);
4531 memcpy(dst
.addr
, src
.addr
, size
);
4534 static void surface_load_sysmem(struct wined3d_surface
*surface
,
4535 const struct wined3d_gl_info
*gl_info
, DWORD dst_location
)
4537 if (surface
->locations
& surface_simple_locations
)
4539 surface_copy_simple_location(surface
, dst_location
);
4543 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
))
4544 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4546 /* Download the surface to system memory. */
4547 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4549 struct wined3d_device
*device
= surface
->resource
.device
;
4550 struct wined3d_context
*context
;
4552 /* TODO: Use already acquired context when possible. */
4553 context
= context_acquire(device
, NULL
);
4555 wined3d_texture_bind_and_dirtify(surface
->container
, context
,
4556 !(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
));
4557 surface_download_data(surface
, gl_info
, dst_location
);
4559 context_release(context
);
4564 if (surface
->locations
& WINED3D_LOCATION_DRAWABLE
)
4566 read_from_framebuffer(surface
, dst_location
);
4570 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
4571 surface
, wined3d_debug_location(surface
->locations
));
4574 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
4575 const struct wined3d_gl_info
*gl_info
)
4579 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& surface_is_offscreen(surface
))
4581 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
4582 return WINED3DERR_INVALIDCALL
;
4585 surface_get_rect(surface
, NULL
, &r
);
4586 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4587 surface_blt_to_drawable(surface
->resource
.device
,
4588 WINED3D_TEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
4593 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
4594 const struct wined3d_gl_info
*gl_info
, BOOL srgb
)
4596 RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4597 struct wined3d_device
*device
= surface
->resource
.device
;
4598 enum wined3d_conversion_type convert
;
4599 struct wined3d_context
*context
;
4600 UINT width
, src_pitch
, dst_pitch
;
4601 struct wined3d_bo_address data
;
4602 struct wined3d_format format
;
4603 POINT dst_point
= {0, 0};
4606 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
4607 && surface_is_offscreen(surface
)
4608 && (surface
->locations
& WINED3D_LOCATION_DRAWABLE
))
4610 surface_load_fb_texture(surface
, srgb
);
4615 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| WINED3D_LOCATION_TEXTURE_RGB
)
4616 && (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
4617 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4618 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4619 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4622 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_RGB
,
4623 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
, &src_rect
);
4625 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
,
4626 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_RGB
, &src_rect
);
4631 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
)
4632 && (!srgb
|| (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
4633 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4634 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4635 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4637 DWORD src_location
= surface
->locations
& WINED3D_LOCATION_RB_RESOLVED
?
4638 WINED3D_LOCATION_RB_RESOLVED
: WINED3D_LOCATION_RB_MULTISAMPLE
;
4639 DWORD dst_location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
4640 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4642 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, src_location
,
4643 &rect
, surface
, dst_location
, &rect
);
4648 /* Upload from system memory */
4650 d3dfmt_get_conv(surface
, TRUE
/* We need color keying */,
4651 TRUE
/* We will use textures */, &format
, &convert
);
4655 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| surface
->map_binding
))
4656 == WINED3D_LOCATION_TEXTURE_RGB
)
4658 /* Performance warning... */
4659 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
4660 surface_prepare_map_memory(surface
);
4661 surface_load_location(surface
, surface
->map_binding
);
4666 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| surface
->map_binding
))
4667 == WINED3D_LOCATION_TEXTURE_SRGB
)
4669 /* Performance warning... */
4670 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
4671 surface_prepare_map_memory(surface
);
4672 surface_load_location(surface
, surface
->map_binding
);
4676 if (!(surface
->locations
& surface_simple_locations
))
4678 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
4679 /* Lets hope we get it from somewhere... */
4680 surface_prepare_system_memory(surface
);
4681 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
4684 /* TODO: Use already acquired context when possible. */
4685 context
= context_acquire(device
, NULL
);
4687 surface_prepare_texture(surface
, context
, srgb
);
4688 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
4690 if (surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
)
4692 surface
->flags
|= SFLAG_GLCKEY
;
4693 surface
->gl_color_key
= surface
->container
->src_blt_color_key
;
4695 else surface
->flags
&= ~SFLAG_GLCKEY
;
4697 width
= surface
->resource
.width
;
4698 src_pitch
= wined3d_surface_get_pitch(surface
);
4700 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
4701 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
4703 if ((convert
!= WINED3D_CT_NONE
|| format
.convert
) && surface
->pbo
)
4705 TRACE("Removing the pbo attached to surface %p.\n", surface
);
4707 if (surface
->flags
& SFLAG_DIBSECTION
)
4708 surface
->map_binding
= WINED3D_LOCATION_DIB
;
4710 surface
->map_binding
= WINED3D_LOCATION_SYSMEM
;
4712 surface_prepare_map_memory(surface
);
4713 surface_load_location(surface
, surface
->map_binding
);
4714 surface_remove_pbo(surface
, gl_info
);
4717 surface_get_memory(surface
, &data
, surface
->locations
);
4720 /* This code is entered for texture formats which need a fixup. */
4721 UINT height
= surface
->resource
.height
;
4723 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4724 dst_pitch
= width
* format
.conv_byte_count
;
4725 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4727 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4729 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4730 context_release(context
);
4731 return E_OUTOFMEMORY
;
4733 format
.convert(data
.addr
, mem
, src_pitch
, src_pitch
* height
,
4734 dst_pitch
, dst_pitch
* height
, width
, height
, 1);
4735 format
.byte_count
= format
.conv_byte_count
;
4736 src_pitch
= dst_pitch
;
4739 else if (convert
!= WINED3D_CT_NONE
)
4741 /* This code is only entered for color keying fixups */
4742 UINT height
= surface
->resource
.height
;
4744 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4745 dst_pitch
= width
* format
.conv_byte_count
;
4746 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4748 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4750 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4751 context_release(context
);
4752 return E_OUTOFMEMORY
;
4754 d3dfmt_convert_surface(data
.addr
, mem
, src_pitch
,
4755 width
, height
, dst_pitch
, convert
, surface
);
4756 format
.byte_count
= format
.conv_byte_count
;
4757 src_pitch
= dst_pitch
;
4761 surface_upload_data(surface
, gl_info
, &format
, &src_rect
, src_pitch
, &dst_point
, srgb
, &data
);
4763 context_release(context
);
4765 HeapFree(GetProcessHeap(), 0, mem
);
4770 static void surface_multisample_resolve(struct wined3d_surface
*surface
)
4772 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4774 if (!(surface
->locations
& WINED3D_LOCATION_RB_MULTISAMPLE
))
4775 ERR("Trying to resolve multisampled surface %p, but location WINED3D_LOCATION_RB_MULTISAMPLE not current.\n",
4778 surface_blt_fbo(surface
->resource
.device
, WINED3D_TEXF_POINT
,
4779 surface
, WINED3D_LOCATION_RB_MULTISAMPLE
, &rect
, surface
, WINED3D_LOCATION_RB_RESOLVED
, &rect
);
4782 HRESULT
surface_load_location(struct wined3d_surface
*surface
, DWORD location
)
4784 struct wined3d_device
*device
= surface
->resource
.device
;
4785 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4788 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4790 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
4792 if (location
== WINED3D_LOCATION_TEXTURE_RGB
4793 && surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_DISCARDED
))
4795 struct wined3d_context
*context
= context_acquire(device
, NULL
);
4796 surface_load_ds_location(surface
, context
, location
);
4797 context_release(context
);
4800 else if (location
& surface
->locations
&& surface
->draw_binding
!= WINED3D_LOCATION_DRAWABLE
)
4802 /* Already up to date, nothing to do. */
4807 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
4808 wined3d_debug_location(surface
->locations
), wined3d_debug_location(location
));
4809 return WINED3DERR_INVALIDCALL
;
4813 if (surface
->locations
& location
)
4815 TRACE("Location already up to date.\n");
4819 if (WARN_ON(d3d_surface
))
4821 DWORD required_access
= resource_access_from_location(location
);
4822 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
4823 WARN("Operation requires %#x access, but surface only has %#x.\n",
4824 required_access
, surface
->resource
.access_flags
);
4827 if (!surface
->locations
)
4829 ERR("Surface %p does not have any up to date location.\n", surface
);
4830 surface
->flags
|= SFLAG_LOST
;
4831 return WINED3DERR_DEVICELOST
;
4836 case WINED3D_LOCATION_DIB
:
4837 case WINED3D_LOCATION_USER_MEMORY
:
4838 case WINED3D_LOCATION_SYSMEM
:
4839 case WINED3D_LOCATION_BUFFER
:
4840 surface_load_sysmem(surface
, gl_info
, location
);
4843 case WINED3D_LOCATION_DRAWABLE
:
4844 if (FAILED(hr
= surface_load_drawable(surface
, gl_info
)))
4848 case WINED3D_LOCATION_RB_RESOLVED
:
4849 surface_multisample_resolve(surface
);
4852 case WINED3D_LOCATION_TEXTURE_RGB
:
4853 case WINED3D_LOCATION_TEXTURE_SRGB
:
4854 if (FAILED(hr
= surface_load_texture(surface
, gl_info
, location
== WINED3D_LOCATION_TEXTURE_SRGB
)))
4859 ERR("Don't know how to handle location %#x.\n", location
);
4863 surface_validate_location(surface
, location
);
4865 if (location
!= WINED3D_LOCATION_SYSMEM
&& (surface
->locations
& WINED3D_LOCATION_SYSMEM
))
4866 surface_evict_sysmem(surface
);
4871 BOOL
surface_is_offscreen(const struct wined3d_surface
*surface
)
4873 struct wined3d_swapchain
*swapchain
;
4875 /* Not on a swapchain - must be offscreen */
4876 if (!(swapchain
= surface
->swapchain
))
4879 /* The front buffer is always onscreen */
4880 if (surface
== swapchain
->front_buffer
) return FALSE
;
4882 /* If the swapchain is rendered to an FBO, the backbuffer is
4883 * offscreen, otherwise onscreen */
4884 return swapchain
->render_to_fbo
;
4887 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
4888 /* Context activation is done by the caller. */
4889 static void ffp_blit_free(struct wined3d_device
*device
) { }
4891 /* Context activation is done by the caller. */
4892 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
4894 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4896 gl_info
->gl_ops
.gl
.p_glEnable(surface
->container
->target
);
4897 checkGLcall("glEnable(target)");
4902 /* Context activation is done by the caller. */
4903 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
4905 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_2D
);
4906 checkGLcall("glDisable(GL_TEXTURE_2D)");
4907 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
4909 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
4910 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4912 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
4914 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_RECTANGLE_ARB
);
4915 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4919 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
4920 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
4921 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
4925 case WINED3D_BLIT_OP_COLOR_BLIT
:
4926 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
4929 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
4931 TRACE("Checking support for fixup:\n");
4932 dump_color_fixup_desc(src_format
->color_fixup
);
4935 /* We only support identity conversions. */
4936 if (!is_identity_fixup(src_format
->color_fixup
)
4937 || !is_identity_fixup(dst_format
->color_fixup
))
4939 TRACE("Fixups are not supported.\n");
4945 case WINED3D_BLIT_OP_COLOR_FILL
:
4946 if (dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
4949 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
4951 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
4954 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
4956 TRACE("Color fill not supported\n");
4960 /* FIXME: We should reject color fills on formats with fixups,
4961 * but this would break P8 color fills for example. */
4965 case WINED3D_BLIT_OP_DEPTH_FILL
:
4969 TRACE("Unsupported blit_op=%d\n", blit_op
);
4974 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
4975 const RECT
*dst_rect
, const struct wined3d_color
*color
)
4977 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
4978 struct wined3d_fb_state fb
= {&dst_surface
, NULL
};
4980 device_clear_render_targets(device
, 1, &fb
, 1, dst_rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
4985 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
,
4986 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
4988 const RECT draw_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4989 struct wined3d_fb_state fb
= {NULL
, surface
};
4991 device_clear_render_targets(device
, 0, &fb
, 1, rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
4996 const struct blit_shader ffp_blit
= {
5002 ffp_blit_color_fill
,
5003 ffp_blit_depth_fill
,
5006 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
5011 /* Context activation is done by the caller. */
5012 static void cpu_blit_free(struct wined3d_device
*device
)
5016 /* Context activation is done by the caller. */
5017 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
5022 /* Context activation is done by the caller. */
5023 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
5027 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
5028 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
5029 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
5031 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
5039 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
5040 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
5041 const struct wined3d_format
*format
, DWORD flags
, const WINEDDBLTFX
*fx
)
5043 UINT row_block_count
;
5044 const BYTE
*src_row
;
5051 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
5055 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5057 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
5058 src_row
+= src_pitch
;
5059 dst_row
+= dst_pitch
;
5065 if (flags
== WINEDDBLT_DDFX
&& fx
->dwDDFX
== WINEDDBLTFX_MIRRORUPDOWN
)
5067 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
5071 case WINED3DFMT_DXT1
:
5072 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5077 BYTE control_row
[4];
5080 const struct block
*s
= (const struct block
*)src_row
;
5081 struct block
*d
= (struct block
*)dst_row
;
5083 for (x
= 0; x
< row_block_count
; ++x
)
5085 d
[x
].color
[0] = s
[x
].color
[0];
5086 d
[x
].color
[1] = s
[x
].color
[1];
5087 d
[x
].control_row
[0] = s
[x
].control_row
[3];
5088 d
[x
].control_row
[1] = s
[x
].control_row
[2];
5089 d
[x
].control_row
[2] = s
[x
].control_row
[1];
5090 d
[x
].control_row
[3] = s
[x
].control_row
[0];
5092 src_row
-= src_pitch
;
5093 dst_row
+= dst_pitch
;
5097 case WINED3DFMT_DXT2
:
5098 case WINED3DFMT_DXT3
:
5099 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5105 BYTE control_row
[4];
5108 const struct block
*s
= (const struct block
*)src_row
;
5109 struct block
*d
= (struct block
*)dst_row
;
5111 for (x
= 0; x
< row_block_count
; ++x
)
5113 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
5114 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
5115 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
5116 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
5117 d
[x
].color
[0] = s
[x
].color
[0];
5118 d
[x
].color
[1] = s
[x
].color
[1];
5119 d
[x
].control_row
[0] = s
[x
].control_row
[3];
5120 d
[x
].control_row
[1] = s
[x
].control_row
[2];
5121 d
[x
].control_row
[2] = s
[x
].control_row
[1];
5122 d
[x
].control_row
[3] = s
[x
].control_row
[0];
5124 src_row
-= src_pitch
;
5125 dst_row
+= dst_pitch
;
5130 FIXME("Compressed flip not implemented for format %s.\n",
5131 debug_d3dformat(format
->id
));
5136 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
5137 debug_d3dformat(format
->id
), flags
, flags
& WINEDDBLT_DDFX
? fx
->dwDDFX
: 0);
5142 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5143 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
5144 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
5146 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
5147 const struct wined3d_format
*src_format
, *dst_format
;
5148 struct wined3d_texture
*src_texture
= NULL
;
5149 struct wined3d_map_desc dst_map
, src_map
;
5150 const BYTE
*sbase
= NULL
;
5151 HRESULT hr
= WINED3D_OK
;
5156 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5157 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5158 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5160 if (src_surface
== dst_surface
)
5162 wined3d_surface_map(dst_surface
, &dst_map
, NULL
, 0);
5164 src_format
= dst_surface
->resource
.format
;
5165 dst_format
= src_format
;
5169 dst_format
= dst_surface
->resource
.format
;
5172 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
5174 if (!(src_texture
= surface_convert_format(src_surface
, dst_format
->id
)))
5176 /* The conv function writes a FIXME */
5177 WARN("Cannot convert source surface format to dest format.\n");
5180 src_surface
= surface_from_resource(wined3d_texture_get_sub_resource(src_texture
, 0));
5182 wined3d_surface_map(src_surface
, &src_map
, NULL
, WINED3D_MAP_READONLY
);
5183 src_format
= src_surface
->resource
.format
;
5187 src_format
= dst_format
;
5190 wined3d_surface_map(dst_surface
, &dst_map
, dst_rect
, 0);
5193 bpp
= dst_surface
->resource
.format
->byte_count
;
5194 srcheight
= src_rect
->bottom
- src_rect
->top
;
5195 srcwidth
= src_rect
->right
- src_rect
->left
;
5196 dstheight
= dst_rect
->bottom
- dst_rect
->top
;
5197 dstwidth
= dst_rect
->right
- dst_rect
->left
;
5198 width
= (dst_rect
->right
- dst_rect
->left
) * bpp
;
5201 sbase
= (BYTE
*)src_map
.data
5202 + ((src_rect
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
5203 + ((src_rect
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
5204 if (src_surface
!= dst_surface
)
5205 dbuf
= dst_map
.data
;
5207 dbuf
= (BYTE
*)dst_map
.data
5208 + ((dst_rect
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
5209 + ((dst_rect
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
5211 if (src_format
->flags
& dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
5213 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
5215 if (src_surface
== dst_surface
)
5217 FIXME("Only plain blits supported on compressed surfaces.\n");
5222 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
5224 WARN("Stretching not supported on compressed surfaces.\n");
5225 hr
= WINED3DERR_INVALIDCALL
;
5229 if (!surface_check_block_align(src_surface
, src_rect
))
5231 WARN("Source rectangle not block-aligned.\n");
5232 hr
= WINED3DERR_INVALIDCALL
;
5236 if (!surface_check_block_align(dst_surface
, dst_rect
))
5238 WARN("Destination rectangle not block-aligned.\n");
5239 hr
= WINED3DERR_INVALIDCALL
;
5243 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
5244 src_map
.row_pitch
, dst_map
.row_pitch
, dstwidth
, dstheight
,
5245 src_format
, flags
, fx
);
5249 /* First, all the 'source-less' blits */
5250 if (flags
& WINEDDBLT_COLORFILL
)
5252 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, fx
->u5
.dwFillColor
);
5253 flags
&= ~WINEDDBLT_COLORFILL
;
5256 if (flags
& WINEDDBLT_DEPTHFILL
)
5258 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
5260 if (flags
& WINEDDBLT_ROP
)
5262 /* Catch some degenerate cases here. */
5266 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, 0);
5268 case 0xaa0029: /* No-op */
5271 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, ~0U);
5273 case SRCCOPY
: /* Well, we do that below? */
5276 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx
->dwROP
, fx
->u5
.lpDDSPattern
);
5279 flags
&= ~WINEDDBLT_ROP
;
5281 if (flags
& WINEDDBLT_DDROPS
)
5283 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx
->dwDDROP
, fx
->u5
.lpDDSPattern
);
5285 /* Now the 'with source' blits. */
5288 int sx
, xinc
, sy
, yinc
;
5290 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
5293 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
5294 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
5296 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
5297 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
5300 xinc
= (srcwidth
<< 16) / dstwidth
;
5301 yinc
= (srcheight
<< 16) / dstheight
;
5305 /* No effects, we can cheat here. */
5306 if (dstwidth
== srcwidth
)
5308 if (dstheight
== srcheight
)
5310 /* No stretching in either direction. This needs to be as
5311 * fast as possible. */
5314 /* Check for overlapping surfaces. */
5315 if (src_surface
!= dst_surface
|| dst_rect
->top
< src_rect
->top
5316 || dst_rect
->right
<= src_rect
->left
|| src_rect
->right
<= dst_rect
->left
)
5318 /* No overlap, or dst above src, so copy from top downwards. */
5319 for (y
= 0; y
< dstheight
; ++y
)
5321 memcpy(dbuf
, sbuf
, width
);
5322 sbuf
+= src_map
.row_pitch
;
5323 dbuf
+= dst_map
.row_pitch
;
5326 else if (dst_rect
->top
> src_rect
->top
)
5328 /* Copy from bottom upwards. */
5329 sbuf
+= src_map
.row_pitch
* dstheight
;
5330 dbuf
+= dst_map
.row_pitch
* dstheight
;
5331 for (y
= 0; y
< dstheight
; ++y
)
5333 sbuf
-= src_map
.row_pitch
;
5334 dbuf
-= dst_map
.row_pitch
;
5335 memcpy(dbuf
, sbuf
, width
);
5340 /* Src and dst overlapping on the same line, use memmove. */
5341 for (y
= 0; y
< dstheight
; ++y
)
5343 memmove(dbuf
, sbuf
, width
);
5344 sbuf
+= src_map
.row_pitch
;
5345 dbuf
+= dst_map
.row_pitch
;
5351 /* Stretching in y direction only. */
5352 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5354 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5355 memcpy(dbuf
, sbuf
, width
);
5356 dbuf
+= dst_map
.row_pitch
;
5362 /* Stretching in X direction. */
5364 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5366 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5368 if ((sy
>> 16) == (last_sy
>> 16))
5370 /* This source row is the same as last source row -
5371 * Copy the already stretched row. */
5372 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, width
);
5376 #define STRETCH_ROW(type) \
5378 const type *s = (const type *)sbuf; \
5379 type *d = (type *)dbuf; \
5380 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5381 d[x] = s[sx >> 16]; \
5399 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
5403 s
= sbuf
+ 3 * (sx
>> 16);
5404 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5405 d
[0] = (pixel
) & 0xff;
5406 d
[1] = (pixel
>> 8) & 0xff;
5407 d
[2] = (pixel
>> 16) & 0xff;
5413 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
5414 hr
= WINED3DERR_NOTAVAILABLE
;
5419 dbuf
+= dst_map
.row_pitch
;
5426 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
5427 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
5428 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
5429 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
5431 /* The color keying flags are checked for correctness in ddraw */
5432 if (flags
& WINEDDBLT_KEYSRC
)
5434 keylow
= src_surface
->container
->src_blt_color_key
.color_space_low_value
;
5435 keyhigh
= src_surface
->container
->src_blt_color_key
.color_space_high_value
;
5437 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
5439 keylow
= fx
->ddckSrcColorkey
.color_space_low_value
;
5440 keyhigh
= fx
->ddckSrcColorkey
.color_space_high_value
;
5443 if (flags
& WINEDDBLT_KEYDEST
)
5445 /* Destination color keys are taken from the source surface! */
5446 destkeylow
= src_surface
->container
->dst_blt_color_key
.color_space_low_value
;
5447 destkeyhigh
= src_surface
->container
->dst_blt_color_key
.color_space_high_value
;
5449 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
5451 destkeylow
= fx
->ddckDestColorkey
.color_space_low_value
;
5452 destkeyhigh
= fx
->ddckDestColorkey
.color_space_high_value
;
5462 get_color_masks(src_format
, masks
);
5467 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
5470 if (flags
& WINEDDBLT_DDFX
)
5472 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
5475 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
5476 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dst_map
.row_pitch
);
5477 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
5479 if (fx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
5481 /* I don't think we need to do anything about this flag */
5482 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
5484 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
5487 dTopRight
= dTopLeft
;
5490 dBottomRight
= dBottomLeft
;
5492 dstxinc
= dstxinc
* -1;
5494 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
5497 dTopLeft
= dBottomLeft
;
5500 dTopRight
= dBottomRight
;
5502 dstyinc
= dstyinc
* -1;
5504 if (fx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
5506 /* I don't think we need to do anything about this flag */
5507 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
5509 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
5512 dBottomRight
= dTopLeft
;
5515 dBottomLeft
= dTopRight
;
5517 dstxinc
= dstxinc
* -1;
5518 dstyinc
= dstyinc
* -1;
5520 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
5523 dTopLeft
= dBottomLeft
;
5524 dBottomLeft
= dBottomRight
;
5525 dBottomRight
= dTopRight
;
5530 dstxinc
= dstxinc
* -1;
5532 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
5535 dTopLeft
= dTopRight
;
5536 dTopRight
= dBottomRight
;
5537 dBottomRight
= dBottomLeft
;
5542 dstyinc
= dstyinc
* -1;
5544 if (fx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
5546 /* I don't think we need to do anything about this flag */
5547 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
5550 flags
&= ~(WINEDDBLT_DDFX
);
5553 #define COPY_COLORKEY_FX(type) \
5556 type *d = (type *)dbuf, *dx, tmp; \
5557 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
5559 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
5561 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5563 tmp = s[sx >> 16]; \
5564 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
5565 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
5569 dx = (type *)(((BYTE *)dx) + dstxinc); \
5571 d = (type *)(((BYTE *)d) + dstyinc); \
5578 COPY_COLORKEY_FX(BYTE
);
5581 COPY_COLORKEY_FX(WORD
);
5584 COPY_COLORKEY_FX(DWORD
);
5589 BYTE
*d
= dbuf
, *dx
;
5590 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5592 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5594 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
5596 DWORD pixel
, dpixel
= 0;
5597 s
= sbuf
+ 3 * (sx
>>16);
5598 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5599 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
5600 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
5601 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
5603 dx
[0] = (pixel
) & 0xff;
5604 dx
[1] = (pixel
>> 8) & 0xff;
5605 dx
[2] = (pixel
>> 16) & 0xff;
5614 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
5615 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
* 8);
5616 hr
= WINED3DERR_NOTAVAILABLE
;
5618 #undef COPY_COLORKEY_FX
5624 if (flags
&& FIXME_ON(d3d_surface
))
5626 FIXME("\tUnsupported flags: %#x.\n", flags
);
5630 wined3d_surface_unmap(dst_surface
);
5631 if (src_surface
&& src_surface
!= dst_surface
)
5632 wined3d_surface_unmap(src_surface
);
5633 /* Release the converted surface, if any. */
5635 wined3d_texture_decref(src_texture
);
5640 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
5641 const RECT
*dst_rect
, const struct wined3d_color
*color
)
5643 static const RECT src_rect
;
5646 memset(&BltFx
, 0, sizeof(BltFx
));
5647 BltFx
.dwSize
= sizeof(BltFx
);
5648 BltFx
.u5
.dwFillColor
= wined3d_format_convert_from_float(dst_surface
, color
);
5649 return surface_cpu_blt(dst_surface
, dst_rect
, NULL
, &src_rect
,
5650 WINEDDBLT_COLORFILL
, &BltFx
, WINED3D_TEXF_POINT
);
5653 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
5654 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
5656 FIXME("Depth filling not implemented by cpu_blit.\n");
5657 return WINED3DERR_INVALIDCALL
;
5660 const struct blit_shader cpu_blit
= {
5666 cpu_blit_color_fill
,
5667 cpu_blit_depth_fill
,
5670 HRESULT CDECL
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
,
5671 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD flags
,
5672 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
5674 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
5675 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5676 DWORD src_ds_flags
, dst_ds_flags
;
5677 RECT src_rect
, dst_rect
;
5678 BOOL scale
, convert
;
5679 enum wined3d_conversion_type dst_convert_type
;
5680 struct wined3d_format dst_conv_fmt
;
5682 static const DWORD simple_blit
= WINEDDBLT_ASYNC
5683 | WINEDDBLT_COLORFILL
5685 | WINEDDBLT_DEPTHFILL
5686 | WINEDDBLT_DONOTWAIT
;
5688 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5689 dst_surface
, wine_dbgstr_rect(dst_rect_in
), src_surface
, wine_dbgstr_rect(src_rect_in
),
5690 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5691 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
5695 TRACE("dwSize %#x.\n", fx
->dwSize
);
5696 TRACE("dwDDFX %#x.\n", fx
->dwDDFX
);
5697 TRACE("dwROP %#x.\n", fx
->dwROP
);
5698 TRACE("dwDDROP %#x.\n", fx
->dwDDROP
);
5699 TRACE("dwRotationAngle %#x.\n", fx
->dwRotationAngle
);
5700 TRACE("dwZBufferOpCode %#x.\n", fx
->dwZBufferOpCode
);
5701 TRACE("dwZBufferLow %#x.\n", fx
->dwZBufferLow
);
5702 TRACE("dwZBufferHigh %#x.\n", fx
->dwZBufferHigh
);
5703 TRACE("dwZBufferBaseDest %#x.\n", fx
->dwZBufferBaseDest
);
5704 TRACE("dwZDestConstBitDepth %#x.\n", fx
->dwZDestConstBitDepth
);
5705 TRACE("lpDDSZBufferDest %p.\n", fx
->u1
.lpDDSZBufferDest
);
5706 TRACE("dwZSrcConstBitDepth %#x.\n", fx
->dwZSrcConstBitDepth
);
5707 TRACE("lpDDSZBufferSrc %p.\n", fx
->u2
.lpDDSZBufferSrc
);
5708 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx
->dwAlphaEdgeBlendBitDepth
);
5709 TRACE("dwAlphaEdgeBlend %#x.\n", fx
->dwAlphaEdgeBlend
);
5710 TRACE("dwReserved %#x.\n", fx
->dwReserved
);
5711 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx
->dwAlphaDestConstBitDepth
);
5712 TRACE("lpDDSAlphaDest %p.\n", fx
->u3
.lpDDSAlphaDest
);
5713 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx
->dwAlphaSrcConstBitDepth
);
5714 TRACE("lpDDSAlphaSrc %p.\n", fx
->u4
.lpDDSAlphaSrc
);
5715 TRACE("lpDDSPattern %p.\n", fx
->u5
.lpDDSPattern
);
5716 TRACE("ddckDestColorkey {%#x, %#x}.\n",
5717 fx
->ddckDestColorkey
.color_space_low_value
,
5718 fx
->ddckDestColorkey
.color_space_high_value
);
5719 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
5720 fx
->ddckSrcColorkey
.color_space_low_value
,
5721 fx
->ddckSrcColorkey
.color_space_high_value
);
5724 if (dst_surface
->resource
.map_count
|| (src_surface
&& src_surface
->resource
.map_count
))
5726 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
5727 return WINEDDERR_SURFACEBUSY
;
5730 surface_get_rect(dst_surface
, dst_rect_in
, &dst_rect
);
5732 if (dst_rect
.left
>= dst_rect
.right
|| dst_rect
.top
>= dst_rect
.bottom
5733 || dst_rect
.left
> dst_surface
->resource
.width
|| dst_rect
.left
< 0
5734 || dst_rect
.top
> dst_surface
->resource
.height
|| dst_rect
.top
< 0
5735 || dst_rect
.right
> dst_surface
->resource
.width
|| dst_rect
.right
< 0
5736 || dst_rect
.bottom
> dst_surface
->resource
.height
|| dst_rect
.bottom
< 0)
5738 WARN("The application gave us a bad destination rectangle.\n");
5739 return WINEDDERR_INVALIDRECT
;
5744 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
5746 if (src_rect
.left
>= src_rect
.right
|| src_rect
.top
>= src_rect
.bottom
5747 || src_rect
.left
> src_surface
->resource
.width
|| src_rect
.left
< 0
5748 || src_rect
.top
> src_surface
->resource
.height
|| src_rect
.top
< 0
5749 || src_rect
.right
> src_surface
->resource
.width
|| src_rect
.right
< 0
5750 || src_rect
.bottom
> src_surface
->resource
.height
|| src_rect
.bottom
< 0)
5752 WARN("Application gave us bad source rectangle for Blt.\n");
5753 return WINEDDERR_INVALIDRECT
;
5758 memset(&src_rect
, 0, sizeof(src_rect
));
5761 if (!fx
|| !(fx
->dwDDFX
))
5762 flags
&= ~WINEDDBLT_DDFX
;
5764 if (flags
& WINEDDBLT_WAIT
)
5765 flags
&= ~WINEDDBLT_WAIT
;
5767 if (flags
& WINEDDBLT_ASYNC
)
5769 static unsigned int once
;
5772 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
5773 flags
&= ~WINEDDBLT_ASYNC
;
5776 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
5777 if (flags
& WINEDDBLT_DONOTWAIT
)
5779 static unsigned int once
;
5782 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
5783 flags
&= ~WINEDDBLT_DONOTWAIT
;
5786 if (!device
->d3d_initialized
)
5788 WARN("D3D not initialized, using fallback.\n");
5792 /* We want to avoid invalidating the sysmem location for converted
5793 * surfaces, since otherwise we'd have to convert the data back when
5795 d3dfmt_get_conv(dst_surface
, TRUE
, TRUE
, &dst_conv_fmt
, &dst_convert_type
);
5796 if (dst_convert_type
!= WINED3D_CT_NONE
|| dst_conv_fmt
.convert
|| dst_surface
->flags
& SFLAG_CONVERTED
)
5798 WARN_(d3d_perf
)("Converted surface, using CPU blit.\n");
5802 if (flags
& ~simple_blit
)
5804 WARN_(d3d_perf
)("Using fallback for complex blit (%#x).\n", flags
);
5809 src_swapchain
= src_surface
->swapchain
;
5811 src_swapchain
= NULL
;
5813 dst_swapchain
= dst_surface
->swapchain
;
5815 /* This isn't strictly needed. FBO blits for example could deal with
5816 * cross-swapchain blits by first downloading the source to a texture
5817 * before switching to the destination context. We just have this here to
5818 * not have to deal with the issue, since cross-swapchain blits should be
5820 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
5822 FIXME("Using fallback for cross-swapchain blit.\n");
5827 && (src_rect
.right
- src_rect
.left
!= dst_rect
.right
- dst_rect
.left
5828 || src_rect
.bottom
- src_rect
.top
!= dst_rect
.bottom
- dst_rect
.top
);
5829 convert
= src_surface
&& src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
;
5831 dst_ds_flags
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5833 src_ds_flags
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5837 if (src_ds_flags
|| dst_ds_flags
)
5839 if (flags
& WINEDDBLT_DEPTHFILL
)
5843 TRACE("Depth fill.\n");
5845 if (!surface_convert_depth_to_float(dst_surface
, fx
->u5
.dwFillDepth
, &depth
))
5846 return WINED3DERR_INVALIDCALL
;
5848 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, &dst_rect
, depth
)))
5853 if (src_ds_flags
!= dst_ds_flags
)
5855 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
5856 return WINED3DERR_INVALIDCALL
;
5859 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_surface
->draw_binding
, &src_rect
,
5860 dst_surface
, dst_surface
->draw_binding
, &dst_rect
)))
5866 /* In principle this would apply to depth blits as well, but we don't
5867 * implement those in the CPU blitter at the moment. */
5868 if ((dst_surface
->locations
& dst_surface
->map_binding
)
5869 && (!src_surface
|| (src_surface
->locations
& src_surface
->map_binding
)))
5872 TRACE("Not doing sysmem blit because of scaling.\n");
5874 TRACE("Not doing sysmem blit because of format conversion.\n");
5879 if (flags
& WINEDDBLT_COLORFILL
)
5881 struct wined3d_color color
;
5883 TRACE("Color fill.\n");
5885 if (!surface_convert_color_to_float(dst_surface
, fx
->u5
.dwFillColor
, &color
))
5888 if (SUCCEEDED(surface_color_fill(dst_surface
, &dst_rect
, &color
)))
5893 TRACE("Color blit.\n");
5896 if ((src_surface
->locations
& WINED3D_LOCATION_SYSMEM
)
5897 && !(dst_surface
->locations
& WINED3D_LOCATION_SYSMEM
))
5900 TRACE("Not doing upload because of scaling.\n");
5902 TRACE("Not doing upload because of format conversion.\n");
5905 POINT dst_point
= {dst_rect
.left
, dst_rect
.top
};
5907 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, &src_rect
)))
5909 if (!surface_is_offscreen(dst_surface
))
5910 surface_load_location(dst_surface
, dst_surface
->draw_binding
);
5916 /* Use present for back -> front blits. The idea behind this is
5917 * that present is potentially faster than a blit, in particular
5918 * when FBO blits aren't available. Some ddraw applications like
5919 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
5920 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
5921 * applications can't blit directly to the frontbuffer. */
5922 if (dst_swapchain
&& dst_swapchain
->back_buffers
5923 && dst_surface
== dst_swapchain
->front_buffer
5924 && src_surface
== dst_swapchain
->back_buffers
[0])
5926 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
5928 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
5930 /* Set the swap effect to COPY, we don't want the backbuffer
5931 * to become undefined. */
5932 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
5933 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, NULL
, 0);
5934 dst_swapchain
->desc
.swap_effect
= swap_effect
;
5939 if (fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5940 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5941 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5943 TRACE("Using FBO blit.\n");
5945 surface_blt_fbo(device
, filter
,
5946 src_surface
, src_surface
->draw_binding
, &src_rect
,
5947 dst_surface
, dst_surface
->draw_binding
, &dst_rect
);
5948 surface_validate_location(dst_surface
, dst_surface
->draw_binding
);
5949 surface_invalidate_location(dst_surface
, ~dst_surface
->draw_binding
);
5954 if (arbfp_blit
.blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5955 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5956 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5958 TRACE("Using arbfp blit.\n");
5960 if (SUCCEEDED(arbfp_blit_surface(device
, filter
, src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
5967 /* Special cases for render targets. */
5968 if (SUCCEEDED(surface_blt_special(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
)))
5973 /* For the rest call the X11 surface implementation. For render targets
5974 * this should be implemented OpenGL accelerated in surface_blt_special(),
5975 * other blits are rather rare. */
5976 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
5979 static HRESULT
surface_init(struct wined3d_surface
*surface
, struct wined3d_texture
*container
,
5980 const struct wined3d_resource_desc
*desc
, GLenum target
, GLint level
, DWORD flags
)
5982 struct wined3d_device
*device
= container
->resource
.device
;
5983 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
5984 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, desc
->format
);
5985 UINT multisample_quality
= desc
->multisample_quality
;
5986 BOOL lockable
= flags
& WINED3D_SURFACE_MAPPABLE
;
5987 unsigned int resource_size
;
5990 if (multisample_quality
> 0)
5992 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality
);
5993 multisample_quality
= 0;
5996 /* Quick lockable sanity check.
5997 * TODO: remove this after surfaces, usage and lockability have been debugged properly
5998 * this function is too deep to need to care about things like this.
5999 * Levels need to be checked too, since they all affect what can be done. */
6002 case WINED3D_POOL_MANAGED
:
6003 if (desc
->usage
& WINED3DUSAGE_DYNAMIC
)
6004 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
6007 case WINED3D_POOL_DEFAULT
:
6008 if (lockable
&& !(desc
->usage
& (WINED3DUSAGE_DYNAMIC
6009 | WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
6010 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
6013 case WINED3D_POOL_SCRATCH
:
6014 case WINED3D_POOL_SYSTEM_MEM
:
6018 FIXME("Unknown pool %#x.\n", desc
->pool
);
6022 if (desc
->usage
& WINED3DUSAGE_RENDERTARGET
&& desc
->pool
!= WINED3D_POOL_DEFAULT
)
6023 FIXME("Trying to create a render target that isn't in the default pool.\n");
6025 /* FIXME: Check that the format is supported by the device. */
6027 resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, desc
->width
, desc
->height
, 1);
6029 return WINED3DERR_INVALIDCALL
;
6031 if (device
->wined3d
->flags
& WINED3D_NO3D
)
6032 surface
->surface_ops
= &gdi_surface_ops
;
6034 surface
->surface_ops
= &surface_ops
;
6036 if (FAILED(hr
= resource_init(&surface
->resource
, device
, WINED3D_RTYPE_SURFACE
, format
,
6037 desc
->multisample_type
, multisample_quality
, desc
->usage
, desc
->pool
, desc
->width
, desc
->height
, 1,
6038 resource_size
, NULL
, &wined3d_null_parent_ops
, &surface_resource_ops
)))
6040 WARN("Failed to initialize resource, returning %#x.\n", hr
);
6044 surface_set_container(surface
, container
);
6045 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
6046 list_init(&surface
->renderbuffers
);
6047 list_init(&surface
->overlays
);
6050 if (target
!= GL_TEXTURE_RECTANGLE_ARB
)
6051 surface
->flags
|= SFLAG_NORMCOORD
;
6052 if (flags
& WINED3D_SURFACE_DISCARD
)
6053 surface
->flags
|= SFLAG_DISCARD
;
6054 if (flags
& WINED3D_SURFACE_PIN_SYSMEM
)
6055 surface
->flags
|= SFLAG_PIN_SYSMEM
;
6056 if (lockable
|| desc
->format
== WINED3DFMT_D16_LOCKABLE
)
6057 surface
->resource
.access_flags
|= WINED3D_RESOURCE_ACCESS_CPU
;
6059 surface
->map_binding
= WINED3D_LOCATION_SYSMEM
;
6060 surface
->texture_target
= target
;
6061 surface
->texture_level
= level
;
6063 /* Call the private setup routine */
6064 hr
= surface
->surface_ops
->surface_private_setup(surface
);
6067 ERR("Private setup failed, returning %#x\n", hr
);
6068 surface_set_container(surface
, NULL
);
6069 surface_cleanup(surface
);
6073 /* Similar to lockable rendertargets above, creating the DIB section
6074 * during surface initialization prevents the sysmem pointer from changing
6075 * after a wined3d_surface_getdc() call. */
6076 if ((desc
->usage
& WINED3DUSAGE_OWNDC
) && !surface
->hDC
6077 && SUCCEEDED(surface_create_dib_section(surface
)))
6078 surface
->map_binding
= WINED3D_LOCATION_DIB
;
6080 if (surface
->map_binding
== WINED3D_LOCATION_DIB
)
6082 wined3d_resource_free_sysmem(&surface
->resource
);
6083 surface_validate_location(surface
, WINED3D_LOCATION_DIB
);
6084 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
6090 HRESULT
wined3d_surface_create(struct wined3d_texture
*container
, const struct wined3d_resource_desc
*desc
,
6091 GLenum target
, GLint level
, DWORD flags
, struct wined3d_surface
**surface
)
6093 struct wined3d_device_parent
*device_parent
= container
->resource
.device
->device_parent
;
6094 const struct wined3d_parent_ops
*parent_ops
;
6095 struct wined3d_surface
*object
;
6099 TRACE("container %p, width %u, height %u, format %s, usage %s (%#x), pool %s, "
6100 "multisample_type %#x, multisample_quality %u, target %#x, level %d, flags %#x, surface %p.\n",
6101 container
, desc
->width
, desc
->height
, debug_d3dformat(desc
->format
),
6102 debug_d3dusage(desc
->usage
), desc
->usage
, debug_d3dpool(desc
->pool
),
6103 desc
->multisample_type
, desc
->multisample_quality
, target
, level
, flags
, surface
);
6105 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
6106 return E_OUTOFMEMORY
;
6108 if (FAILED(hr
= surface_init(object
, container
, desc
, target
, level
, flags
)))
6110 WARN("Failed to initialize surface, returning %#x.\n", hr
);
6111 HeapFree(GetProcessHeap(), 0, object
);
6115 if (FAILED(hr
= device_parent
->ops
->surface_created(device_parent
,
6116 wined3d_texture_get_parent(container
), object
, &parent
, &parent_ops
)))
6118 WARN("Failed to create surface parent, hr %#x.\n", hr
);
6119 surface_set_container(object
, NULL
);
6120 wined3d_surface_decref(object
);
6124 TRACE("Created surface %p, parent %p, parent_ops %p.\n", object
, parent
, parent_ops
);
6126 object
->resource
.parent
= parent
;
6127 object
->resource
.parent_ops
= parent_ops
;