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
);
501 TRACE("Using wined3d palette %p.\n", surface
->palette
);
503 surface
->flags
|= SFLAG_DIBSECTION
;
508 static void surface_get_memory(const struct wined3d_surface
*surface
, struct wined3d_bo_address
*data
,
511 if (location
& WINED3D_LOCATION_BUFFER
)
514 data
->buffer_object
= surface
->pbo
;
517 if (location
& WINED3D_LOCATION_USER_MEMORY
)
519 data
->addr
= surface
->user_memory
;
520 data
->buffer_object
= 0;
523 if (location
& WINED3D_LOCATION_DIB
)
525 data
->addr
= surface
->dib
.bitmap_data
;
526 data
->buffer_object
= 0;
529 if (location
& WINED3D_LOCATION_SYSMEM
)
531 data
->addr
= surface
->resource
.heap_memory
;
532 data
->buffer_object
= 0;
536 ERR("Unexpected locations %s.\n", wined3d_debug_location(location
));
538 data
->buffer_object
= 0;
541 static void surface_prepare_buffer(struct wined3d_surface
*surface
)
543 struct wined3d_context
*context
;
545 const struct wined3d_gl_info
*gl_info
;
550 context
= context_acquire(surface
->resource
.device
, NULL
);
551 gl_info
= context
->gl_info
;
553 GL_EXTCALL(glGenBuffersARB(1, &surface
->pbo
));
554 error
= gl_info
->gl_ops
.gl
.p_glGetError();
555 if (!surface
->pbo
|| error
!= GL_NO_ERROR
)
556 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error
), error
);
558 TRACE("Binding PBO %u.\n", surface
->pbo
);
560 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
561 checkGLcall("glBindBufferARB");
563 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->resource
.size
+ 4,
564 NULL
, GL_STREAM_DRAW_ARB
));
565 checkGLcall("glBufferDataARB");
567 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
568 checkGLcall("glBindBufferARB");
570 context_release(context
);
573 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
575 TRACE("surface %p.\n", surface
);
577 if (surface
->resource
.heap_memory
)
580 /* Whatever surface we have, make sure that there is memory allocated
581 * for the downloaded copy, or a PBO to map. */
582 if (!wined3d_resource_allocate_sysmem(&surface
->resource
))
583 ERR("Failed to allocate system memory.\n");
585 if (surface
->locations
& WINED3D_LOCATION_SYSMEM
)
586 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
589 void surface_prepare_map_memory(struct wined3d_surface
*surface
)
591 switch (surface
->map_binding
)
593 case WINED3D_LOCATION_SYSMEM
:
594 surface_prepare_system_memory(surface
);
597 case WINED3D_LOCATION_USER_MEMORY
:
598 if (!surface
->user_memory
)
599 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
602 case WINED3D_LOCATION_DIB
:
603 if (!surface
->dib
.bitmap_data
)
604 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
607 case WINED3D_LOCATION_BUFFER
:
608 surface_prepare_buffer(surface
);
612 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->map_binding
));
616 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
618 if (surface
->resource
.map_count
|| surface
->flags
& SFLAG_DONOTFREE
)
621 wined3d_resource_free_sysmem(&surface
->resource
);
622 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
625 static void surface_force_reload(struct wined3d_surface
*surface
)
627 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
630 static void surface_release_client_storage(struct wined3d_surface
*surface
)
632 struct wined3d_context
*context
= context_acquire(surface
->resource
.device
, NULL
);
633 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
635 if (surface
->container
->texture_rgb
.name
)
637 wined3d_texture_bind_and_dirtify(surface
->container
, context
, FALSE
);
638 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
639 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
641 if (surface
->container
->texture_srgb
.name
)
643 wined3d_texture_bind_and_dirtify(surface
->container
, context
, TRUE
);
644 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
645 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
648 context_release(context
);
650 surface_invalidate_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
);
651 surface_force_reload(surface
);
654 static BOOL
surface_use_pbo(const struct wined3d_surface
*surface
)
656 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
658 return surface
->resource
.pool
== WINED3D_POOL_DEFAULT
659 && surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
660 && gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
]
661 && !surface
->resource
.format
->convert
662 && !(surface
->flags
& (SFLAG_NONPOW2
| SFLAG_PIN_SYSMEM
));
665 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
667 /* TODO: Check against the maximum texture sizes supported by the video card. */
668 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
669 unsigned int pow2Width
, pow2Height
;
671 TRACE("surface %p.\n", surface
);
673 /* Non-power2 support */
674 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
]
675 || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
677 pow2Width
= surface
->resource
.width
;
678 pow2Height
= surface
->resource
.height
;
682 /* Find the nearest pow2 match */
683 pow2Width
= pow2Height
= 1;
684 while (pow2Width
< surface
->resource
.width
)
686 while (pow2Height
< surface
->resource
.height
)
689 surface
->pow2Width
= pow2Width
;
690 surface
->pow2Height
= pow2Height
;
692 if (pow2Width
> surface
->resource
.width
|| pow2Height
> surface
->resource
.height
)
694 /* TODO: Add support for non power two compressed textures. */
695 if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_HEIGHT_SCALE
))
697 FIXME("(%p) Compressed or height scaled non-power-two textures are not supported w(%d) h(%d)\n",
698 surface
, surface
->resource
.width
, surface
->resource
.height
);
699 return WINED3DERR_NOTAVAILABLE
;
703 if (pow2Width
!= surface
->resource
.width
704 || pow2Height
!= surface
->resource
.height
)
706 surface
->flags
|= SFLAG_NONPOW2
;
709 if ((surface
->pow2Width
> gl_info
->limits
.texture_size
|| surface
->pow2Height
> gl_info
->limits
.texture_size
)
710 && !(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
712 /* One of three options:
713 * 1: Do the same as we do with NPOT and scale the texture, (any
714 * texture ops would require the texture to be scaled which is
716 * 2: Set the texture to the maximum size (bad idea).
717 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
718 * 4: Create the surface, but allow it to be used only for DirectDraw
719 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
720 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
721 * the render target. */
722 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
|| surface
->resource
.pool
== WINED3D_POOL_MANAGED
)
724 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
725 return WINED3DERR_NOTAVAILABLE
;
728 /* We should never use this surface in combination with OpenGL! */
729 TRACE("Creating an oversized surface: %ux%u.\n",
730 surface
->pow2Width
, surface
->pow2Height
);
733 switch (wined3d_settings
.offscreen_rendering_mode
)
736 surface
->get_drawable_size
= get_drawable_size_fbo
;
740 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
744 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
745 return WINED3DERR_INVALIDCALL
;
748 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
749 surface
->locations
= WINED3D_LOCATION_DISCARDED
;
751 if (surface_use_pbo(surface
))
752 surface
->map_binding
= WINED3D_LOCATION_BUFFER
;
757 static void surface_realize_palette(struct wined3d_surface
*surface
)
759 struct wined3d_palette
*palette
= surface
->palette
;
761 TRACE("surface %p.\n", surface
);
763 if (!palette
) return;
765 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
766 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
768 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
770 /* Make sure the texture is up to date. This call doesn't do
771 * anything if the texture is already up to date. */
772 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
774 /* We want to force a palette refresh, so mark the drawable as not being up to date */
775 if (!surface_is_offscreen(surface
))
776 surface_invalidate_location(surface
, WINED3D_LOCATION_DRAWABLE
);
780 if (!(surface
->locations
& surface
->map_binding
))
782 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
783 surface_prepare_map_memory(surface
);
784 surface_load_location(surface
, surface
->map_binding
);
786 surface_invalidate_location(surface
, ~surface
->map_binding
);
790 if (surface
->flags
& SFLAG_DIBSECTION
)
792 TRACE("Updating the DC's palette.\n");
793 SetDIBColorTable(surface
->hDC
, 0, 256, palette
->colors
);
796 /* Propagate the changes to the drawable when we have a palette. */
797 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
798 surface_load_location(surface
, surface
->draw_binding
);
801 static void surface_unmap(struct wined3d_surface
*surface
)
803 struct wined3d_device
*device
= surface
->resource
.device
;
804 const struct wined3d_gl_info
*gl_info
;
805 struct wined3d_context
*context
;
807 TRACE("surface %p.\n", surface
);
809 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
811 switch (surface
->map_binding
)
813 case WINED3D_LOCATION_SYSMEM
:
814 case WINED3D_LOCATION_USER_MEMORY
:
815 case WINED3D_LOCATION_DIB
:
818 case WINED3D_LOCATION_BUFFER
:
819 context
= context_acquire(device
, NULL
);
820 gl_info
= context
->gl_info
;
822 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
823 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
824 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
825 checkGLcall("glUnmapBufferARB");
826 context_release(context
);
830 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->map_binding
));
833 if (surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_TEXTURE_RGB
))
835 TRACE("Not dirtified, nothing to do.\n");
839 if (surface
->swapchain
&& surface
->swapchain
->front_buffer
== surface
)
840 surface_load_location(surface
, surface
->draw_binding
);
841 else if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
842 FIXME("Depth / stencil buffer locking is not implemented.\n");
845 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
847 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
849 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
854 static void surface_depth_blt_fbo(const struct wined3d_device
*device
,
855 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
856 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
858 const struct wined3d_gl_info
*gl_info
;
859 struct wined3d_context
*context
;
860 DWORD src_mask
, dst_mask
;
863 TRACE("device %p\n", device
);
864 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
865 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect
));
866 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
867 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect
));
869 src_mask
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
870 dst_mask
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
872 if (src_mask
!= dst_mask
)
874 ERR("Incompatible formats %s and %s.\n",
875 debug_d3dformat(src_surface
->resource
.format
->id
),
876 debug_d3dformat(dst_surface
->resource
.format
->id
));
882 ERR("Not a depth / stencil format: %s.\n",
883 debug_d3dformat(src_surface
->resource
.format
->id
));
888 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
889 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
890 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
891 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
893 /* Make sure the locations are up-to-date. Loading the destination
894 * surface isn't required if the entire surface is overwritten. */
895 surface_load_location(src_surface
, src_location
);
896 if (!surface_is_full_rect(dst_surface
, dst_rect
))
897 surface_load_location(dst_surface
, dst_location
);
899 context
= context_acquire(device
, NULL
);
902 context_release(context
);
903 WARN("Invalid context, skipping blit.\n");
907 gl_info
= context
->gl_info
;
909 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, src_location
);
910 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
912 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, dst_location
);
913 context_set_draw_buffer(context
, GL_NONE
);
914 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
915 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
917 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
919 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
920 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
922 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
924 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
926 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
927 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
929 gl_info
->gl_ops
.gl
.p_glStencilMask(~0U);
930 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
933 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
934 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
936 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
937 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
938 checkGLcall("glBlitFramebuffer()");
940 if (wined3d_settings
.strict_draw_ordering
)
941 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
943 context_release(context
);
946 /* Blit between surface locations. Onscreen on different swapchains is not supported.
947 * Depth / stencil is not supported. */
948 static void surface_blt_fbo(const struct wined3d_device
*device
, enum wined3d_texture_filter_type filter
,
949 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
950 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
952 const struct wined3d_gl_info
*gl_info
;
953 struct wined3d_context
*context
;
954 RECT src_rect
, dst_rect
;
958 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
959 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
960 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect_in
));
961 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
962 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect_in
));
964 src_rect
= *src_rect_in
;
965 dst_rect
= *dst_rect_in
;
969 case WINED3D_TEXF_LINEAR
:
970 gl_filter
= GL_LINEAR
;
974 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
975 case WINED3D_TEXF_NONE
:
976 case WINED3D_TEXF_POINT
:
977 gl_filter
= GL_NEAREST
;
981 /* Resolve the source surface first if needed. */
982 if (src_location
== WINED3D_LOCATION_RB_MULTISAMPLE
983 && (src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
984 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
985 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
986 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
988 /* Make sure the locations are up-to-date. Loading the destination
989 * surface isn't required if the entire surface is overwritten. (And is
990 * in fact harmful if we're being called by surface_load_location() with
991 * the purpose of loading the destination surface.) */
992 surface_load_location(src_surface
, src_location
);
993 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
994 surface_load_location(dst_surface
, dst_location
);
996 if (src_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, src_surface
);
997 else if (dst_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, dst_surface
);
998 else context
= context_acquire(device
, NULL
);
1000 if (!context
->valid
)
1002 context_release(context
);
1003 WARN("Invalid context, skipping blit.\n");
1007 gl_info
= context
->gl_info
;
1009 if (src_location
== WINED3D_LOCATION_DRAWABLE
)
1011 TRACE("Source surface %p is onscreen.\n", src_surface
);
1012 buffer
= surface_get_gl_buffer(src_surface
);
1013 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
1017 TRACE("Source surface %p is offscreen.\n", src_surface
);
1018 buffer
= GL_COLOR_ATTACHMENT0
;
1021 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
1022 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
1023 checkGLcall("glReadBuffer()");
1024 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1026 if (dst_location
== WINED3D_LOCATION_DRAWABLE
)
1028 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
1029 buffer
= surface_get_gl_buffer(dst_surface
);
1030 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
1034 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
1035 buffer
= GL_COLOR_ATTACHMENT0
;
1038 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
1039 context_set_draw_buffer(context
, buffer
);
1040 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1041 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
1043 gl_info
->gl_ops
.gl
.p_glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
1044 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
1045 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
1046 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
1047 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
1049 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
1050 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
1052 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
1053 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
1054 checkGLcall("glBlitFramebuffer()");
1056 if (wined3d_settings
.strict_draw_ordering
1057 || (dst_location
== WINED3D_LOCATION_DRAWABLE
1058 && dst_surface
->swapchain
->front_buffer
== dst_surface
))
1059 gl_info
->gl_ops
.gl
.p_glFlush();
1061 context_release(context
);
1064 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
1065 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
1066 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
1068 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
1071 /* Source and/or destination need to be on the GL side */
1072 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
1077 case WINED3D_BLIT_OP_COLOR_BLIT
:
1078 if (!((src_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
1080 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
1084 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1085 if (!(src_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1087 if (!(dst_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1095 if (!(src_format
->id
== dst_format
->id
1096 || (is_identity_fixup(src_format
->color_fixup
)
1097 && is_identity_fixup(dst_format
->color_fixup
))))
1103 static BOOL
surface_convert_color_to_float(const struct wined3d_surface
*surface
,
1104 DWORD color
, struct wined3d_color
*float_color
)
1106 const struct wined3d_format
*format
= surface
->resource
.format
;
1110 case WINED3DFMT_P8_UINT
:
1111 if (surface
->palette
)
1113 float_color
->r
= surface
->palette
->colors
[color
].rgbRed
/ 255.0f
;
1114 float_color
->g
= surface
->palette
->colors
[color
].rgbGreen
/ 255.0f
;
1115 float_color
->b
= surface
->palette
->colors
[color
].rgbBlue
/ 255.0f
;
1119 float_color
->r
= 0.0f
;
1120 float_color
->g
= 0.0f
;
1121 float_color
->b
= 0.0f
;
1123 float_color
->a
= color
/ 255.0f
;
1126 case WINED3DFMT_B5G6R5_UNORM
:
1127 float_color
->r
= ((color
>> 11) & 0x1f) / 31.0f
;
1128 float_color
->g
= ((color
>> 5) & 0x3f) / 63.0f
;
1129 float_color
->b
= (color
& 0x1f) / 31.0f
;
1130 float_color
->a
= 1.0f
;
1133 case WINED3DFMT_B8G8R8_UNORM
:
1134 case WINED3DFMT_B8G8R8X8_UNORM
:
1135 float_color
->r
= D3DCOLOR_R(color
);
1136 float_color
->g
= D3DCOLOR_G(color
);
1137 float_color
->b
= D3DCOLOR_B(color
);
1138 float_color
->a
= 1.0f
;
1141 case WINED3DFMT_B8G8R8A8_UNORM
:
1142 float_color
->r
= D3DCOLOR_R(color
);
1143 float_color
->g
= D3DCOLOR_G(color
);
1144 float_color
->b
= D3DCOLOR_B(color
);
1145 float_color
->a
= D3DCOLOR_A(color
);
1149 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1156 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1158 const struct wined3d_format
*format
= surface
->resource
.format
;
1162 case WINED3DFMT_S1_UINT_D15_UNORM
:
1163 *float_depth
= depth
/ (float)0x00007fff;
1166 case WINED3DFMT_D16_UNORM
:
1167 *float_depth
= depth
/ (float)0x0000ffff;
1170 case WINED3DFMT_D24_UNORM_S8_UINT
:
1171 case WINED3DFMT_X8D24_UNORM
:
1172 *float_depth
= depth
/ (float)0x00ffffff;
1175 case WINED3DFMT_D32_UNORM
:
1176 *float_depth
= depth
/ (float)0xffffffff;
1180 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1187 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1189 const struct wined3d_resource
*resource
= &surface
->resource
;
1190 struct wined3d_device
*device
= resource
->device
;
1191 const struct blit_shader
*blitter
;
1193 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_FILL
,
1194 NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
);
1197 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1198 return WINED3DERR_INVALIDCALL
;
1201 return blitter
->depth_fill(device
, surface
, rect
, depth
);
1204 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
1205 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
1207 struct wined3d_device
*device
= src_surface
->resource
.device
;
1209 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1210 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1211 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1212 return WINED3DERR_INVALIDCALL
;
1214 surface_depth_blt_fbo(device
, src_surface
, src_location
, src_rect
, dst_surface
, dst_location
, dst_rect
);
1216 surface_modify_ds_location(dst_surface
, dst_location
,
1217 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1222 HRESULT CDECL
wined3d_surface_get_render_target_data(struct wined3d_surface
*surface
,
1223 struct wined3d_surface
*render_target
)
1225 TRACE("surface %p, render_target %p.\n", surface
, render_target
);
1227 /* TODO: Check surface sizes, pools, etc. */
1229 if (render_target
->resource
.multisample_type
)
1230 return WINED3DERR_INVALIDCALL
;
1232 return wined3d_surface_blt(surface
, NULL
, render_target
, NULL
, 0, NULL
, WINED3D_TEXF_POINT
);
1235 /* Context activation is done by the caller. */
1236 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1238 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
1239 checkGLcall("glDeleteBuffersARB(1, &surface->pbo)");
1242 surface_invalidate_location(surface
, WINED3D_LOCATION_BUFFER
);
1245 static void surface_unload(struct wined3d_resource
*resource
)
1247 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1248 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1249 struct wined3d_device
*device
= resource
->device
;
1250 const struct wined3d_gl_info
*gl_info
;
1251 struct wined3d_context
*context
;
1253 TRACE("surface %p.\n", surface
);
1255 if (resource
->pool
== WINED3D_POOL_DEFAULT
)
1257 /* Default pool resources are supposed to be destroyed before Reset is called.
1258 * Implicit resources stay however. So this means we have an implicit render target
1259 * or depth stencil. The content may be destroyed, but we still have to tear down
1260 * opengl resources, so we cannot leave early.
1262 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1263 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1264 * or the depth stencil into an FBO the texture or render buffer will be removed
1265 * and all flags get lost */
1266 surface_prepare_system_memory(surface
);
1267 memset(surface
->resource
.heap_memory
, 0, surface
->resource
.size
);
1268 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
1269 surface_invalidate_location(surface
, ~WINED3D_LOCATION_SYSMEM
);
1271 /* We also get here when the ddraw swapchain is destroyed, for example
1272 * for a mode switch. In this case this surface won't necessarily be
1273 * an implicit surface. We have to mark it lost so that the
1274 * application can restore it after the mode switch. */
1275 surface
->flags
|= SFLAG_LOST
;
1279 surface_prepare_map_memory(surface
);
1280 surface_load_location(surface
, surface
->map_binding
);
1281 surface_invalidate_location(surface
, ~surface
->map_binding
);
1283 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
1285 context
= context_acquire(device
, NULL
);
1286 gl_info
= context
->gl_info
;
1288 /* Destroy PBOs, but load them into real sysmem before */
1290 surface_remove_pbo(surface
, gl_info
);
1292 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1293 * all application-created targets the application has to release the surface
1294 * before calling _Reset
1296 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1298 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1299 list_remove(&entry
->entry
);
1300 HeapFree(GetProcessHeap(), 0, entry
);
1302 list_init(&surface
->renderbuffers
);
1303 surface
->current_renderbuffer
= NULL
;
1305 if (surface
->rb_multisample
)
1307 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
1308 surface
->rb_multisample
= 0;
1310 if (surface
->rb_resolved
)
1312 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
1313 surface
->rb_resolved
= 0;
1316 context_release(context
);
1318 resource_unload(resource
);
1321 static const struct wined3d_resource_ops surface_resource_ops
=
1326 static const struct wined3d_surface_ops surface_ops
=
1328 surface_private_setup
,
1329 surface_realize_palette
,
1333 /*****************************************************************************
1334 * Initializes the GDI surface, aka creates the DIB section we render to
1335 * The DIB section creation is done by calling GetDC, which will create the
1336 * section and releasing the dc to allow the app to use it. The dib section
1337 * will stay until the surface is released
1339 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1340 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1341 * avoid confusion in the shared surface code.
1344 * WINED3D_OK on success
1345 * The return values of called methods on failure
1347 *****************************************************************************/
1348 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1352 TRACE("surface %p.\n", surface
);
1354 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1356 ERR("Overlays not yet supported by GDI surfaces.\n");
1357 return WINED3DERR_INVALIDCALL
;
1360 /* Sysmem textures have memory already allocated - release it,
1361 * this avoids an unnecessary memcpy. */
1362 hr
= surface_create_dib_section(surface
);
1365 surface
->map_binding
= WINED3D_LOCATION_DIB
;
1367 /* We don't mind the nonpow2 stuff in GDI. */
1368 surface
->pow2Width
= surface
->resource
.width
;
1369 surface
->pow2Height
= surface
->resource
.height
;
1374 static void gdi_surface_realize_palette(struct wined3d_surface
*surface
)
1376 struct wined3d_palette
*palette
= surface
->palette
;
1378 TRACE("surface %p.\n", surface
);
1380 if (!palette
) return;
1382 if (surface
->flags
& SFLAG_DIBSECTION
)
1384 TRACE("Updating the DC's palette.\n");
1385 SetDIBColorTable(surface
->hDC
, 0, 256, palette
->colors
);
1388 /* Update the image because of the palette change. Some games like e.g.
1389 * Red Alert call SetEntries a lot to implement fading. */
1390 /* Tell the swapchain to update the screen. */
1391 if (surface
->swapchain
&& surface
== surface
->swapchain
->front_buffer
)
1392 x11_copy_to_screen(surface
->swapchain
, NULL
);
1395 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
1397 TRACE("surface %p.\n", surface
);
1399 /* Tell the swapchain to update the screen. */
1400 if (surface
->swapchain
&& surface
== surface
->swapchain
->front_buffer
)
1401 x11_copy_to_screen(surface
->swapchain
, &surface
->lockedRect
);
1403 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
1406 static const struct wined3d_surface_ops gdi_surface_ops
=
1408 gdi_surface_private_setup
,
1409 gdi_surface_realize_palette
,
1413 /* This call just downloads data, the caller is responsible for binding the
1414 * correct texture. */
1415 /* Context activation is done by the caller. */
1416 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1419 const struct wined3d_format
*format
= surface
->resource
.format
;
1420 struct wined3d_bo_address data
;
1422 /* Only support read back of converted P8 surfaces. */
1423 if (surface
->flags
& SFLAG_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
1425 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
1429 surface_get_memory(surface
, &data
, dst_location
);
1431 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1433 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
1434 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, data
.addr
);
1436 if (data
.buffer_object
)
1438 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
1439 checkGLcall("glBindBufferARB");
1440 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
, surface
->texture_level
, NULL
));
1441 checkGLcall("glGetCompressedTexImageARB");
1442 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
1443 checkGLcall("glBindBufferARB");
1447 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
,
1448 surface
->texture_level
, data
.addr
));
1449 checkGLcall("glGetCompressedTexImageARB");
1455 GLenum gl_format
= format
->glFormat
;
1456 GLenum gl_type
= format
->glType
;
1460 if (format
->id
== WINED3DFMT_P8_UINT
)
1462 gl_format
= GL_ALPHA
;
1463 gl_type
= GL_UNSIGNED_BYTE
;
1466 if (surface
->flags
& SFLAG_NONPOW2
)
1468 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
1469 src_pitch
= format
->byte_count
* surface
->pow2Width
;
1470 dst_pitch
= wined3d_surface_get_pitch(surface
);
1471 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
1472 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
1479 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1480 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
1482 if (data
.buffer_object
)
1484 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
1485 checkGLcall("glBindBufferARB");
1487 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1488 gl_format
, gl_type
, NULL
);
1489 checkGLcall("glGetTexImage");
1491 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
1492 checkGLcall("glBindBufferARB");
1496 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1497 gl_format
, gl_type
, mem
);
1498 checkGLcall("glGetTexImage");
1501 if (surface
->flags
& SFLAG_NONPOW2
)
1503 const BYTE
*src_data
;
1507 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1508 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1509 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1511 * We're doing this...
1513 * instead of boxing the texture :
1514 * |<-texture width ->| -->pow2width| /\
1515 * |111111111111111111| | |
1516 * |222 Texture 222222| boxed empty | texture height
1517 * |3333 Data 33333333| | |
1518 * |444444444444444444| | \/
1519 * ----------------------------------- |
1520 * | boxed empty | boxed empty | pow2height
1522 * -----------------------------------
1525 * we're repacking the data to the expected texture width
1527 * |<-texture width ->| -->pow2width| /\
1528 * |111111111111111111222222222222222| |
1529 * |222333333333333333333444444444444| texture height
1533 * | empty | pow2height
1535 * -----------------------------------
1539 * |<-texture width ->| /\
1540 * |111111111111111111|
1541 * |222222222222222222|texture height
1542 * |333333333333333333|
1543 * |444444444444444444| \/
1544 * --------------------
1546 * This also means that any references to surface memory should work with the data as if it were a
1547 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1549 * internally the texture is still stored in a boxed format so any references to textureName will
1550 * get a boxed texture with width pow2width and not a texture of width resource.width.
1552 * Performance should not be an issue, because applications normally do not lock the surfaces when
1553 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
1554 * and doesn't have to be re-read. */
1556 dst_data
= data
.addr
;
1557 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_pitch
);
1558 for (y
= 0; y
< surface
->resource
.height
; ++y
)
1560 memcpy(dst_data
, src_data
, dst_pitch
);
1561 src_data
+= src_pitch
;
1562 dst_data
+= dst_pitch
;
1565 HeapFree(GetProcessHeap(), 0, mem
);
1570 /* This call just uploads data, the caller is responsible for binding the
1571 * correct texture. */
1572 /* Context activation is done by the caller. */
1573 static void surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1574 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
1575 BOOL srgb
, const struct wined3d_bo_address
*data
)
1577 UINT update_w
= src_rect
->right
- src_rect
->left
;
1578 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
1580 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1581 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
1582 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
1584 if (surface
->resource
.map_count
)
1586 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
1587 surface
->flags
|= SFLAG_PIN_SYSMEM
;
1590 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
1592 update_h
*= format
->height_scale
.numerator
;
1593 update_h
/= format
->height_scale
.denominator
;
1596 if (data
->buffer_object
)
1598 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, data
->buffer_object
));
1599 checkGLcall("glBindBufferARB");
1602 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1604 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1, 1);
1605 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
1606 const BYTE
*addr
= data
->addr
;
1609 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
1610 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
1613 internal
= format
->glGammaInternal
;
1614 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
1615 internal
= format
->rtInternal
;
1617 internal
= format
->glInternal
;
1619 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
1620 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
1621 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
1623 if (row_length
== src_pitch
)
1625 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1626 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
1632 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
1633 * can't use the unpack row length like below. */
1634 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
1636 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1637 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
1638 y
+= format
->block_height
;
1642 checkGLcall("glCompressedTexSubImage2DARB");
1646 const BYTE
*addr
= data
->addr
;
1648 addr
+= src_rect
->top
* src_pitch
;
1649 addr
+= src_rect
->left
* format
->byte_count
;
1651 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1652 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
1653 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1655 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
1656 gl_info
->gl_ops
.gl
.p_glTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1657 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1658 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1659 checkGLcall("glTexSubImage2D");
1662 if (data
->buffer_object
)
1664 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
1665 checkGLcall("glBindBufferARB");
1668 if (wined3d_settings
.strict_draw_ordering
)
1669 gl_info
->gl_ops
.gl
.p_glFlush();
1671 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
1673 struct wined3d_device
*device
= surface
->resource
.device
;
1676 for (i
= 0; i
< device
->context_count
; ++i
)
1678 context_surface_update(device
->contexts
[i
], surface
);
1683 static HRESULT
d3dfmt_get_conv(const struct wined3d_surface
*surface
, BOOL need_alpha_ck
, BOOL use_texturing
,
1684 struct wined3d_format
*format
, enum wined3d_conversion_type
*conversion_type
)
1686 BOOL colorkey_active
= need_alpha_ck
&& (surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
);
1687 const struct wined3d_device
*device
= surface
->resource
.device
;
1688 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1689 BOOL blit_supported
= FALSE
;
1691 /* Copy the default values from the surface. Below we might perform fixups */
1692 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
1693 *format
= *surface
->resource
.format
;
1694 *conversion_type
= WINED3D_CT_NONE
;
1696 /* Ok, now look if we have to do any conversion */
1697 switch (surface
->resource
.format
->id
)
1699 case WINED3DFMT_P8_UINT
:
1700 /* Below the call to blit_supported is disabled for Wine 1.2
1701 * because the function isn't operating correctly yet. At the
1702 * moment 8-bit blits are handled in software and if certain GL
1703 * extensions are around, surface conversion is performed at
1704 * upload time. The blit_supported call recognizes it as a
1705 * destination fixup. This type of upload 'fixup' and 8-bit to
1706 * 8-bit blits need to be handled by the blit_shader.
1707 * TODO: get rid of this #if 0. */
1709 blit_supported
= device
->blitter
->blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
1710 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
1711 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
);
1713 blit_supported
= gl_info
->supported
[ARB_FRAGMENT_PROGRAM
];
1715 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
1716 * texturing. Further also use conversion in case of color keying.
1717 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
1718 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
1719 * conflicts with this.
1721 if (!((blit_supported
&& surface
->swapchain
&& surface
== surface
->swapchain
->front_buffer
))
1722 || colorkey_active
|| !use_texturing
)
1724 format
->glFormat
= GL_RGBA
;
1725 format
->glInternal
= GL_RGBA
;
1726 format
->glType
= GL_UNSIGNED_BYTE
;
1727 format
->conv_byte_count
= 4;
1728 if (colorkey_active
)
1729 *conversion_type
= WINED3D_CT_PALETTED_CK
;
1731 *conversion_type
= WINED3D_CT_PALETTED
;
1735 case WINED3DFMT_B2G3R3_UNORM
:
1736 /* **********************
1737 GL_UNSIGNED_BYTE_3_3_2
1738 ********************** */
1739 if (colorkey_active
) {
1740 /* This texture format will never be used.. So do not care about color keying
1741 up until the point in time it will be needed :-) */
1742 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1746 case WINED3DFMT_B5G6R5_UNORM
:
1747 if (colorkey_active
)
1749 *conversion_type
= WINED3D_CT_CK_565
;
1750 format
->glFormat
= GL_RGBA
;
1751 format
->glInternal
= GL_RGB5_A1
;
1752 format
->glType
= GL_UNSIGNED_SHORT_5_5_5_1
;
1753 format
->conv_byte_count
= 2;
1757 case WINED3DFMT_B5G5R5X1_UNORM
:
1758 if (colorkey_active
)
1760 *conversion_type
= WINED3D_CT_CK_5551
;
1761 format
->glFormat
= GL_BGRA
;
1762 format
->glInternal
= GL_RGB5_A1
;
1763 format
->glType
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
1764 format
->conv_byte_count
= 2;
1768 case WINED3DFMT_B8G8R8_UNORM
:
1769 if (colorkey_active
)
1771 *conversion_type
= WINED3D_CT_CK_RGB24
;
1772 format
->glFormat
= GL_RGBA
;
1773 format
->glInternal
= GL_RGBA8
;
1774 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
1775 format
->conv_byte_count
= 4;
1779 case WINED3DFMT_B8G8R8X8_UNORM
:
1780 if (colorkey_active
)
1782 *conversion_type
= WINED3D_CT_RGB32_888
;
1783 format
->glFormat
= GL_RGBA
;
1784 format
->glInternal
= GL_RGBA8
;
1785 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
1786 format
->conv_byte_count
= 4;
1790 case WINED3DFMT_B8G8R8A8_UNORM
:
1791 if (colorkey_active
)
1793 *conversion_type
= WINED3D_CT_CK_ARGB32
;
1794 format
->conv_byte_count
= 4;
1802 if (*conversion_type
!= WINED3D_CT_NONE
)
1804 format
->rtInternal
= format
->glInternal
;
1805 format
->glGammaInternal
= format
->glInternal
;
1811 static BOOL
surface_check_block_align(struct wined3d_surface
*surface
, const RECT
*rect
)
1813 UINT width_mask
, height_mask
;
1815 if (!rect
->left
&& !rect
->top
1816 && rect
->right
== surface
->resource
.width
1817 && rect
->bottom
== surface
->resource
.height
)
1820 /* This assumes power of two block sizes, but NPOT block sizes would be
1822 width_mask
= surface
->resource
.format
->block_width
- 1;
1823 height_mask
= surface
->resource
.format
->block_height
- 1;
1825 if (!(rect
->left
& width_mask
) && !(rect
->top
& height_mask
)
1826 && !(rect
->right
& width_mask
) && !(rect
->bottom
& height_mask
))
1832 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
1833 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
1835 const struct wined3d_format
*src_format
;
1836 const struct wined3d_format
*dst_format
;
1837 const struct wined3d_gl_info
*gl_info
;
1838 enum wined3d_conversion_type convert
;
1839 struct wined3d_context
*context
;
1840 struct wined3d_bo_address data
;
1841 struct wined3d_format format
;
1842 UINT update_w
, update_h
;
1848 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1849 dst_surface
, wine_dbgstr_point(dst_point
),
1850 src_surface
, wine_dbgstr_rect(src_rect
));
1852 src_format
= src_surface
->resource
.format
;
1853 dst_format
= dst_surface
->resource
.format
;
1855 if (src_format
->id
!= dst_format
->id
)
1857 WARN("Source and destination surfaces should have the same format.\n");
1858 return WINED3DERR_INVALIDCALL
;
1867 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
1869 WARN("Invalid destination point.\n");
1870 return WINED3DERR_INVALIDCALL
;
1877 r
.right
= src_surface
->resource
.width
;
1878 r
.bottom
= src_surface
->resource
.height
;
1881 else if (src_rect
->left
< 0 || src_rect
->left
>= src_rect
->right
1882 || src_rect
->top
< 0 || src_rect
->top
>= src_rect
->bottom
)
1884 WARN("Invalid source rectangle.\n");
1885 return WINED3DERR_INVALIDCALL
;
1888 dst_w
= dst_surface
->resource
.width
;
1889 dst_h
= dst_surface
->resource
.height
;
1891 update_w
= src_rect
->right
- src_rect
->left
;
1892 update_h
= src_rect
->bottom
- src_rect
->top
;
1894 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
1895 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
1897 WARN("Destination out of bounds.\n");
1898 return WINED3DERR_INVALIDCALL
;
1901 if ((src_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(src_surface
, src_rect
))
1903 WARN("Source rectangle not block-aligned.\n");
1904 return WINED3DERR_INVALIDCALL
;
1907 SetRect(&dst_rect
, dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
);
1908 if ((dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(dst_surface
, &dst_rect
))
1910 WARN("Destination rectangle not block-aligned.\n");
1911 return WINED3DERR_INVALIDCALL
;
1914 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1915 d3dfmt_get_conv(dst_surface
, FALSE
, TRUE
, &format
, &convert
);
1916 if (convert
!= WINED3D_CT_NONE
|| format
.convert
)
1917 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
1919 context
= context_acquire(dst_surface
->resource
.device
, NULL
);
1920 gl_info
= context
->gl_info
;
1922 /* Only load the surface for partial updates. For newly allocated texture
1923 * the texture wouldn't be the current location, and we'd upload zeroes
1924 * just to overwrite them again. */
1925 if (update_w
== dst_w
&& update_h
== dst_h
)
1926 surface_prepare_texture(dst_surface
, context
, FALSE
);
1928 surface_load_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1929 wined3d_texture_bind(dst_surface
->container
, context
, FALSE
);
1931 surface_get_memory(src_surface
, &data
, src_surface
->locations
);
1932 src_pitch
= wined3d_surface_get_pitch(src_surface
);
1934 surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
, src_pitch
, dst_point
, FALSE
, &data
);
1936 context_invalidate_active_texture(context
);
1938 context_release(context
);
1940 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1941 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1946 /* This call just allocates the texture, the caller is responsible for binding
1947 * the correct texture. */
1948 /* Context activation is done by the caller. */
1949 static void surface_allocate_surface(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1950 const struct wined3d_format
*format
, BOOL srgb
)
1952 BOOL disable_client_storage
= FALSE
;
1953 GLsizei width
= surface
->pow2Width
;
1954 GLsizei height
= surface
->pow2Height
;
1955 const BYTE
*mem
= NULL
;
1960 internal
= format
->glGammaInternal
;
1962 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
1964 internal
= format
->rtInternal
;
1968 internal
= format
->glInternal
;
1972 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format
->id
));
1974 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
1976 height
*= format
->height_scale
.numerator
;
1977 height
/= format
->height_scale
.denominator
;
1980 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",
1981 surface
, surface
->texture_target
, surface
->texture_level
, debug_d3dformat(format
->id
),
1982 internal
, width
, height
, format
->glFormat
, format
->glType
);
1984 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1986 if (surface
->flags
& (SFLAG_NONPOW2
| SFLAG_DIBSECTION
| SFLAG_CONVERTED
)
1987 || !surface
->resource
.heap_memory
)
1989 /* In some cases we want to disable client storage.
1990 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
1991 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
1992 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
1993 * heap_memory == NULL: Not defined in the extension. Seems to disable client storage effectively
1995 surface
->flags
&= ~SFLAG_CLIENT
;
1999 surface
->flags
|= SFLAG_CLIENT
;
2000 mem
= surface
->resource
.heap_memory
;
2002 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2003 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2004 disable_client_storage
= TRUE
;
2008 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
&& mem
)
2010 GL_EXTCALL(glCompressedTexImage2DARB(surface
->texture_target
, surface
->texture_level
,
2011 internal
, width
, height
, 0, surface
->resource
.size
, mem
));
2012 checkGLcall("glCompressedTexImage2DARB");
2016 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
2017 internal
, width
, height
, 0, format
->glFormat
, format
->glType
, mem
);
2018 checkGLcall("glTexImage2D");
2021 if (disable_client_storage
)
2023 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2024 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2028 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2029 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2030 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2031 /* Context activation is done by the caller. */
2032 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
2034 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
2035 struct wined3d_renderbuffer_entry
*entry
;
2036 GLuint renderbuffer
= 0;
2037 unsigned int src_width
, src_height
;
2038 unsigned int width
, height
;
2040 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
2042 width
= rt
->pow2Width
;
2043 height
= rt
->pow2Height
;
2047 width
= surface
->pow2Width
;
2048 height
= surface
->pow2Height
;
2051 src_width
= surface
->pow2Width
;
2052 src_height
= surface
->pow2Height
;
2054 /* A depth stencil smaller than the render target is not valid */
2055 if (width
> src_width
|| height
> src_height
) return;
2057 /* Remove any renderbuffer set if the sizes match */
2058 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
2059 || (width
== src_width
&& height
== src_height
))
2061 surface
->current_renderbuffer
= NULL
;
2065 /* Look if we've already got a renderbuffer of the correct dimensions */
2066 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
2068 if (entry
->width
== width
&& entry
->height
== height
)
2070 renderbuffer
= entry
->id
;
2071 surface
->current_renderbuffer
= entry
;
2078 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
2079 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
2080 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
2081 surface
->resource
.format
->glInternal
, width
, height
);
2083 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
2084 entry
->width
= width
;
2085 entry
->height
= height
;
2086 entry
->id
= renderbuffer
;
2087 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
2089 surface
->current_renderbuffer
= entry
;
2092 checkGLcall("set_compatible_renderbuffer");
2095 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
2097 const struct wined3d_swapchain
*swapchain
= surface
->swapchain
;
2099 TRACE("surface %p.\n", surface
);
2103 ERR("Surface %p is not on a swapchain.\n", surface
);
2107 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
)
2109 if (swapchain
->render_to_fbo
)
2111 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2112 return GL_COLOR_ATTACHMENT0
;
2114 TRACE("Returning GL_BACK\n");
2117 else if (surface
== swapchain
->front_buffer
)
2119 TRACE("Returning GL_FRONT\n");
2123 FIXME("Higher back buffer, returning GL_BACK\n");
2127 void surface_load(struct wined3d_surface
*surface
, BOOL srgb
)
2129 DWORD location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
2132 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
2134 if (surface
->resource
.pool
== WINED3D_POOL_SCRATCH
)
2135 ERR("Not supported on scratch surfaces.\n");
2137 ck_changed
= !(surface
->flags
& SFLAG_GLCKEY
) != !(surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
);
2139 /* Reload if either the texture and sysmem have different ideas about the
2140 * color key, or the actual key values changed. */
2141 if (ck_changed
|| ((surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
)
2142 && (surface
->gl_color_key
.color_space_low_value
2143 != surface
->container
->src_blt_color_key
.color_space_low_value
2144 || surface
->gl_color_key
.color_space_high_value
2145 != surface
->container
->src_blt_color_key
.color_space_high_value
)))
2147 TRACE("Reloading because of color keying\n");
2148 /* To perform the color key conversion we need a sysmem copy of
2149 * the surface. Make sure we have it. */
2151 surface_prepare_map_memory(surface
);
2152 surface_load_location(surface
, surface
->map_binding
);
2153 surface_invalidate_location(surface
, ~surface
->map_binding
);
2154 /* Switching color keying on / off may change the internal format. */
2156 surface_force_reload(surface
);
2158 else if (!(surface
->locations
& location
))
2160 TRACE("Reloading because surface is dirty.\n");
2164 TRACE("surface is already in texture\n");
2168 surface_load_location(surface
, location
);
2169 surface_evict_sysmem(surface
);
2172 /* See also float_16_to_32() in wined3d_private.h */
2173 static inline unsigned short float_32_to_16(const float *in
)
2176 float tmp
= fabsf(*in
);
2177 unsigned int mantissa
;
2180 /* Deal with special numbers */
2186 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
2188 if (tmp
< powf(2, 10))
2194 } while (tmp
< powf(2, 10));
2196 else if (tmp
>= powf(2, 11))
2202 } while (tmp
>= powf(2, 11));
2205 mantissa
= (unsigned int)tmp
;
2206 if (tmp
- mantissa
>= 0.5f
)
2207 ++mantissa
; /* Round to nearest, away from zero. */
2209 exp
+= 10; /* Normalize the mantissa. */
2210 exp
+= 15; /* Exponent is encoded with excess 15. */
2212 if (exp
> 30) /* too big */
2214 ret
= 0x7c00; /* INF */
2218 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2221 mantissa
= mantissa
>> 1;
2224 ret
= mantissa
& 0x3ff;
2228 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
2231 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
2235 ULONG CDECL
wined3d_surface_incref(struct wined3d_surface
*surface
)
2239 TRACE("surface %p, swapchain %p, container %p.\n",
2240 surface
, surface
->swapchain
, surface
->container
);
2242 if (surface
->swapchain
)
2243 return wined3d_swapchain_incref(surface
->swapchain
);
2245 if (surface
->container
)
2246 return wined3d_texture_incref(surface
->container
);
2248 refcount
= InterlockedIncrement(&surface
->resource
.ref
);
2249 TRACE("%p increasing refcount to %u.\n", surface
, refcount
);
2254 ULONG CDECL
wined3d_surface_decref(struct wined3d_surface
*surface
)
2258 TRACE("surface %p, swapchain %p, container %p.\n",
2259 surface
, surface
->swapchain
, surface
->container
);
2261 if (surface
->swapchain
)
2262 return wined3d_swapchain_decref(surface
->swapchain
);
2264 if (surface
->container
)
2265 return wined3d_texture_decref(surface
->container
);
2267 refcount
= InterlockedDecrement(&surface
->resource
.ref
);
2268 TRACE("%p decreasing refcount to %u.\n", surface
, refcount
);
2272 surface_cleanup(surface
);
2273 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
2275 TRACE("Destroyed surface %p.\n", surface
);
2276 HeapFree(GetProcessHeap(), 0, surface
);
2282 DWORD CDECL
wined3d_surface_set_priority(struct wined3d_surface
*surface
, DWORD priority
)
2284 return resource_set_priority(&surface
->resource
, priority
);
2287 DWORD CDECL
wined3d_surface_get_priority(const struct wined3d_surface
*surface
)
2289 return resource_get_priority(&surface
->resource
);
2292 void CDECL
wined3d_surface_preload(struct wined3d_surface
*surface
)
2294 TRACE("surface %p.\n", surface
);
2296 if (!surface
->resource
.device
->d3d_initialized
)
2298 ERR("D3D not initialized.\n");
2302 wined3d_texture_preload(surface
->container
);
2305 void * CDECL
wined3d_surface_get_parent(const struct wined3d_surface
*surface
)
2307 TRACE("surface %p.\n", surface
);
2309 return surface
->resource
.parent
;
2312 struct wined3d_resource
* CDECL
wined3d_surface_get_resource(struct wined3d_surface
*surface
)
2314 TRACE("surface %p.\n", surface
);
2316 return &surface
->resource
;
2319 HRESULT CDECL
wined3d_surface_get_blt_status(const struct wined3d_surface
*surface
, DWORD flags
)
2321 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2325 case WINEDDGBS_CANBLT
:
2326 case WINEDDGBS_ISBLTDONE
:
2330 return WINED3DERR_INVALIDCALL
;
2334 HRESULT CDECL
wined3d_surface_get_flip_status(const struct wined3d_surface
*surface
, DWORD flags
)
2336 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2338 /* XXX: DDERR_INVALIDSURFACETYPE */
2342 case WINEDDGFS_CANFLIP
:
2343 case WINEDDGFS_ISFLIPDONE
:
2347 return WINED3DERR_INVALIDCALL
;
2351 HRESULT CDECL
wined3d_surface_is_lost(const struct wined3d_surface
*surface
)
2353 TRACE("surface %p.\n", surface
);
2355 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2356 return surface
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
2359 HRESULT CDECL
wined3d_surface_restore(struct wined3d_surface
*surface
)
2361 TRACE("surface %p.\n", surface
);
2363 surface
->flags
&= ~SFLAG_LOST
;
2367 void CDECL
wined3d_surface_set_palette(struct wined3d_surface
*surface
, struct wined3d_palette
*palette
)
2369 TRACE("surface %p, palette %p.\n", surface
, palette
);
2371 if (surface
->palette
== palette
)
2373 TRACE("Nop palette change.\n");
2377 surface
->palette
= palette
;
2379 surface
->surface_ops
->surface_realize_palette(surface
);
2382 DWORD CDECL
wined3d_surface_get_pitch(const struct wined3d_surface
*surface
)
2384 unsigned int alignment
;
2387 TRACE("surface %p.\n", surface
);
2390 return surface
->pitch
;
2392 alignment
= surface
->resource
.device
->surface_alignment
;
2393 pitch
= wined3d_format_calculate_pitch(surface
->resource
.format
, surface
->resource
.width
);
2394 pitch
= (pitch
+ alignment
- 1) & ~(alignment
- 1);
2396 TRACE("Returning %u.\n", pitch
);
2401 HRESULT CDECL
wined3d_surface_set_overlay_position(struct wined3d_surface
*surface
, LONG x
, LONG y
)
2405 TRACE("surface %p, x %d, y %d.\n", surface
, x
, y
);
2407 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2409 WARN("Not an overlay surface.\n");
2410 return WINEDDERR_NOTAOVERLAYSURFACE
;
2413 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
2414 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
2415 surface
->overlay_destrect
.left
= x
;
2416 surface
->overlay_destrect
.top
= y
;
2417 surface
->overlay_destrect
.right
= x
+ w
;
2418 surface
->overlay_destrect
.bottom
= y
+ h
;
2423 HRESULT CDECL
wined3d_surface_get_overlay_position(const struct wined3d_surface
*surface
, LONG
*x
, LONG
*y
)
2425 TRACE("surface %p, x %p, y %p.\n", surface
, x
, y
);
2427 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2429 TRACE("Not an overlay surface.\n");
2430 return WINEDDERR_NOTAOVERLAYSURFACE
;
2433 if (!surface
->overlay_dest
)
2435 TRACE("Overlay not visible.\n");
2438 return WINEDDERR_OVERLAYNOTVISIBLE
;
2441 *x
= surface
->overlay_destrect
.left
;
2442 *y
= surface
->overlay_destrect
.top
;
2444 TRACE("Returning position %d, %d.\n", *x
, *y
);
2449 HRESULT CDECL
wined3d_surface_update_overlay_z_order(struct wined3d_surface
*surface
,
2450 DWORD flags
, struct wined3d_surface
*ref
)
2452 FIXME("surface %p, flags %#x, ref %p stub!\n", surface
, flags
, ref
);
2454 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2456 TRACE("Not an overlay surface.\n");
2457 return WINEDDERR_NOTAOVERLAYSURFACE
;
2463 HRESULT CDECL
wined3d_surface_update_overlay(struct wined3d_surface
*surface
, const RECT
*src_rect
,
2464 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
, DWORD flags
, const WINEDDOVERLAYFX
*fx
)
2466 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2467 surface
, wine_dbgstr_rect(src_rect
), dst_surface
, wine_dbgstr_rect(dst_rect
), flags
, fx
);
2469 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2471 WARN("Not an overlay surface.\n");
2472 return WINEDDERR_NOTAOVERLAYSURFACE
;
2474 else if (!dst_surface
)
2476 WARN("Dest surface is NULL.\n");
2477 return WINED3DERR_INVALIDCALL
;
2482 surface
->overlay_srcrect
= *src_rect
;
2486 surface
->overlay_srcrect
.left
= 0;
2487 surface
->overlay_srcrect
.top
= 0;
2488 surface
->overlay_srcrect
.right
= surface
->resource
.width
;
2489 surface
->overlay_srcrect
.bottom
= surface
->resource
.height
;
2494 surface
->overlay_destrect
= *dst_rect
;
2498 surface
->overlay_destrect
.left
= 0;
2499 surface
->overlay_destrect
.top
= 0;
2500 surface
->overlay_destrect
.right
= dst_surface
? dst_surface
->resource
.width
: 0;
2501 surface
->overlay_destrect
.bottom
= dst_surface
? dst_surface
->resource
.height
: 0;
2504 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
2506 surface
->overlay_dest
= NULL
;
2507 list_remove(&surface
->overlay_entry
);
2510 if (flags
& WINEDDOVER_SHOW
)
2512 if (surface
->overlay_dest
!= dst_surface
)
2514 surface
->overlay_dest
= dst_surface
;
2515 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
2518 else if (flags
& WINEDDOVER_HIDE
)
2520 /* tests show that the rectangles are erased on hide */
2521 surface
->overlay_srcrect
.left
= 0; surface
->overlay_srcrect
.top
= 0;
2522 surface
->overlay_srcrect
.right
= 0; surface
->overlay_srcrect
.bottom
= 0;
2523 surface
->overlay_destrect
.left
= 0; surface
->overlay_destrect
.top
= 0;
2524 surface
->overlay_destrect
.right
= 0; surface
->overlay_destrect
.bottom
= 0;
2525 surface
->overlay_dest
= NULL
;
2531 HRESULT CDECL
wined3d_surface_update_desc(struct wined3d_surface
*surface
,
2532 UINT width
, UINT height
, enum wined3d_format_id format_id
,
2533 enum wined3d_multisample_type multisample_type
, UINT multisample_quality
,
2534 void *mem
, UINT pitch
)
2536 struct wined3d_device
*device
= surface
->resource
.device
;
2537 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
2538 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
2539 UINT resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, width
, height
, 1);
2540 BOOL create_dib
= FALSE
;
2542 DWORD valid_location
= 0;
2544 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u, "
2545 "mem %p, pitch %u.\n",
2546 surface
, width
, height
, debug_d3dformat(format_id
), multisample_type
, multisample_type
, mem
, pitch
);
2549 return WINED3DERR_INVALIDCALL
;
2551 if (surface
->resource
.map_count
|| (surface
->flags
& SFLAG_DCINUSE
))
2553 WARN("Surface is mapped or the DC is in use.\n");
2554 return WINED3DERR_INVALIDCALL
;
2557 if (device
->d3d_initialized
)
2558 surface
->resource
.resource_ops
->resource_unload(&surface
->resource
);
2560 if (surface
->flags
& SFLAG_DIBSECTION
)
2562 DeleteDC(surface
->hDC
);
2563 DeleteObject(surface
->dib
.DIBsection
);
2564 surface
->dib
.bitmap_data
= NULL
;
2565 surface
->flags
&= ~SFLAG_DIBSECTION
;
2569 surface
->locations
= 0;
2570 wined3d_resource_free_sysmem(&surface
->resource
);
2572 surface
->resource
.width
= width
;
2573 surface
->resource
.height
= height
;
2574 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
2575 || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
2577 surface
->pow2Width
= width
;
2578 surface
->pow2Height
= height
;
2582 surface
->pow2Width
= surface
->pow2Height
= 1;
2583 while (surface
->pow2Width
< width
)
2584 surface
->pow2Width
<<= 1;
2585 while (surface
->pow2Height
< height
)
2586 surface
->pow2Height
<<= 1;
2589 if (surface
->pow2Width
!= width
|| surface
->pow2Height
!= height
)
2590 surface
->flags
|= SFLAG_NONPOW2
;
2592 surface
->flags
&= ~SFLAG_NONPOW2
;
2594 surface
->user_memory
= mem
;
2595 if (surface
->user_memory
)
2597 surface
->map_binding
= WINED3D_LOCATION_USER_MEMORY
;
2598 valid_location
= WINED3D_LOCATION_USER_MEMORY
;
2600 surface
->pitch
= pitch
;
2601 surface
->resource
.format
= format
;
2602 surface
->resource
.multisample_type
= multisample_type
;
2603 surface
->resource
.multisample_quality
= multisample_quality
;
2605 surface
->resource
.size
= height
* surface
->pitch
;
2607 surface
->resource
.size
= resource_size
;
2609 /* The format might be changed to a format that needs conversion.
2610 * If the surface didn't use PBOs previously but could now, don't
2611 * change it - whatever made us not use PBOs might come back, e.g.
2613 if (surface
->map_binding
== WINED3D_LOCATION_BUFFER
&& !surface_use_pbo(surface
))
2614 surface
->map_binding
= create_dib
? WINED3D_LOCATION_DIB
: WINED3D_LOCATION_SYSMEM
;
2618 if (FAILED(hr
= surface_create_dib_section(surface
)))
2620 ERR("Failed to create dib section, hr %#x.\n", hr
);
2623 if (!valid_location
)
2624 valid_location
= WINED3D_LOCATION_DIB
;
2627 if (!valid_location
)
2629 surface_prepare_system_memory(surface
);
2630 valid_location
= WINED3D_LOCATION_SYSMEM
;
2633 surface_validate_location(surface
, valid_location
);
2638 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
2639 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2641 unsigned short *dst_s
;
2645 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2647 for (y
= 0; y
< h
; ++y
)
2649 src_f
= (const float *)(src
+ y
* pitch_in
);
2650 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
2651 for (x
= 0; x
< w
; ++x
)
2653 dst_s
[x
] = float_32_to_16(src_f
+ x
);
2658 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2659 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2661 static const unsigned char convert_5to8
[] =
2663 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
2664 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
2665 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
2666 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
2668 static const unsigned char convert_6to8
[] =
2670 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
2671 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
2672 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
2673 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
2674 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
2675 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
2676 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
2677 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
2681 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2683 for (y
= 0; y
< h
; ++y
)
2685 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
2686 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2687 for (x
= 0; x
< w
; ++x
)
2689 WORD pixel
= src_line
[x
];
2690 dst_line
[x
] = 0xff000000
2691 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
2692 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
2693 | convert_5to8
[(pixel
& 0x001f)];
2698 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
2699 * in both cases we're just setting the X / Alpha channel to 0xff. */
2700 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2701 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2705 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2707 for (y
= 0; y
< h
; ++y
)
2709 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
2710 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2712 for (x
= 0; x
< w
; ++x
)
2714 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
2719 static inline BYTE
cliptobyte(int x
)
2721 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
2724 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2725 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2727 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2730 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2732 for (y
= 0; y
< h
; ++y
)
2734 const BYTE
*src_line
= src
+ y
* pitch_in
;
2735 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2736 for (x
= 0; x
< w
; ++x
)
2738 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2739 * C = Y - 16; D = U - 128; E = V - 128;
2740 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2741 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2742 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2743 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2744 * U and V are shared between the pixels. */
2745 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2747 d
= (int) src_line
[1] - 128;
2748 e
= (int) src_line
[3] - 128;
2750 g2
= - 100 * d
- 208 * e
+ 128;
2753 c2
= 298 * ((int) src_line
[0] - 16);
2754 dst_line
[x
] = 0xff000000
2755 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
2756 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
2757 | cliptobyte((c2
+ b2
) >> 8); /* blue */
2758 /* Scale RGB values to 0..255 range,
2759 * then clip them if still not in range (may be negative),
2760 * then shift them within DWORD if necessary. */
2766 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
2767 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2770 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2772 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
2774 for (y
= 0; y
< h
; ++y
)
2776 const BYTE
*src_line
= src
+ y
* pitch_in
;
2777 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
2778 for (x
= 0; x
< w
; ++x
)
2780 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2781 * C = Y - 16; D = U - 128; E = V - 128;
2782 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2783 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2784 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2785 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2786 * U and V are shared between the pixels. */
2787 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2789 d
= (int) src_line
[1] - 128;
2790 e
= (int) src_line
[3] - 128;
2792 g2
= - 100 * d
- 208 * e
+ 128;
2795 c2
= 298 * ((int) src_line
[0] - 16);
2796 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
2797 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
2798 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
2799 /* Scale RGB values to 0..255 range,
2800 * then clip them if still not in range (may be negative),
2801 * then shift them within DWORD if necessary. */
2807 struct d3dfmt_converter_desc
2809 enum wined3d_format_id from
, to
;
2810 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
2813 static const struct d3dfmt_converter_desc converters
[] =
2815 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
2816 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
2817 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2818 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2819 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
2820 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
2823 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
2824 enum wined3d_format_id to
)
2828 for (i
= 0; i
< (sizeof(converters
) / sizeof(*converters
)); ++i
)
2830 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
2831 return &converters
[i
];
2837 static struct wined3d_texture
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
2839 struct wined3d_map_desc src_map
, dst_map
;
2840 const struct d3dfmt_converter_desc
*conv
;
2841 struct wined3d_texture
*ret
= NULL
;
2842 struct wined3d_resource_desc desc
;
2843 struct wined3d_surface
*dst
;
2845 conv
= find_converter(source
->resource
.format
->id
, to_fmt
);
2848 FIXME("Cannot find a conversion function from format %s to %s.\n",
2849 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
2853 /* FIXME: Multisampled conversion? */
2854 wined3d_resource_get_desc(&source
->resource
, &desc
);
2855 desc
.resource_type
= WINED3D_RTYPE_TEXTURE
;
2856 desc
.format
= to_fmt
;
2858 desc
.pool
= WINED3D_POOL_SCRATCH
;
2859 if (FAILED(wined3d_texture_create(source
->resource
.device
, &desc
, 1,
2860 WINED3D_SURFACE_MAPPABLE
| WINED3D_SURFACE_DISCARD
, NULL
, &wined3d_null_parent_ops
, &ret
)))
2862 ERR("Failed to create a destination surface for conversion.\n");
2865 dst
= surface_from_resource(wined3d_texture_get_sub_resource(ret
, 0));
2867 memset(&src_map
, 0, sizeof(src_map
));
2868 memset(&dst_map
, 0, sizeof(dst_map
));
2870 if (FAILED(wined3d_surface_map(source
, &src_map
, NULL
, WINED3D_MAP_READONLY
)))
2872 ERR("Failed to lock the source surface.\n");
2873 wined3d_texture_decref(ret
);
2876 if (FAILED(wined3d_surface_map(dst
, &dst_map
, NULL
, 0)))
2878 ERR("Failed to lock the destination surface.\n");
2879 wined3d_surface_unmap(source
);
2880 wined3d_texture_decref(ret
);
2884 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
,
2885 source
->resource
.width
, source
->resource
.height
);
2887 wined3d_surface_unmap(dst
);
2888 wined3d_surface_unmap(source
);
2893 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
2894 unsigned int bpp
, UINT pitch
, DWORD color
)
2901 #define COLORFILL_ROW(type) \
2903 type *d = (type *)buf; \
2904 for (x = 0; x < width; ++x) \
2905 d[x] = (type)color; \
2911 COLORFILL_ROW(BYTE
);
2915 COLORFILL_ROW(WORD
);
2921 for (x
= 0; x
< width
; ++x
, d
+= 3)
2923 d
[0] = (color
) & 0xff;
2924 d
[1] = (color
>> 8) & 0xff;
2925 d
[2] = (color
>> 16) & 0xff;
2930 COLORFILL_ROW(DWORD
);
2934 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
2935 return WINED3DERR_NOTAVAILABLE
;
2938 #undef COLORFILL_ROW
2940 /* Now copy first row. */
2942 for (y
= 1; y
< height
; ++y
)
2945 memcpy(buf
, first
, width
* bpp
);
2951 struct wined3d_surface
* CDECL
wined3d_surface_from_resource(struct wined3d_resource
*resource
)
2953 return surface_from_resource(resource
);
2956 HRESULT CDECL
wined3d_surface_unmap(struct wined3d_surface
*surface
)
2958 TRACE("surface %p.\n", surface
);
2960 if (!surface
->resource
.map_count
)
2962 WARN("Trying to unmap unmapped surface.\n");
2963 return WINEDDERR_NOTLOCKED
;
2965 --surface
->resource
.map_count
;
2967 surface
->surface_ops
->surface_unmap(surface
);
2972 HRESULT CDECL
wined3d_surface_map(struct wined3d_surface
*surface
,
2973 struct wined3d_map_desc
*map_desc
, const RECT
*rect
, DWORD flags
)
2975 const struct wined3d_format
*format
= surface
->resource
.format
;
2976 struct wined3d_device
*device
= surface
->resource
.device
;
2977 struct wined3d_context
*context
;
2978 const struct wined3d_gl_info
*gl_info
;
2981 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
2982 surface
, map_desc
, wine_dbgstr_rect(rect
), flags
);
2984 if (surface
->resource
.map_count
)
2986 WARN("Surface is already mapped.\n");
2987 return WINED3DERR_INVALIDCALL
;
2990 if ((format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && rect
2991 && !surface_check_block_align(surface
, rect
))
2993 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
2994 wine_dbgstr_rect(rect
), format
->block_width
, format
->block_height
);
2996 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
)
2997 return WINED3DERR_INVALIDCALL
;
3000 ++surface
->resource
.map_count
;
3002 if (!(surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
))
3003 WARN("Trying to lock unlockable surface.\n");
3005 /* Performance optimization: Count how often a surface is mapped, if it is
3006 * mapped regularly do not throw away the system memory copy. This avoids
3007 * the need to download the surface from OpenGL all the time. The surface
3008 * is still downloaded if the OpenGL texture is changed. */
3009 if (!(surface
->flags
& SFLAG_DYNLOCK
) && surface
->map_binding
== WINED3D_LOCATION_SYSMEM
)
3011 if (++surface
->lockCount
> MAXLOCKCOUNT
)
3013 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
3014 surface
->flags
|= SFLAG_DYNLOCK
;
3018 surface_prepare_map_memory(surface
);
3019 if (flags
& WINED3D_MAP_DISCARD
)
3021 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
3022 wined3d_debug_location(surface
->map_binding
));
3023 surface_validate_location(surface
, surface
->map_binding
);
3027 if (surface
->resource
.usage
& WINED3DUSAGE_DYNAMIC
)
3028 WARN_(d3d_perf
)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
3030 surface_load_location(surface
, surface
->map_binding
);
3033 if (!(flags
& (WINED3D_MAP_NO_DIRTY_UPDATE
| WINED3D_MAP_READONLY
)))
3034 surface_invalidate_location(surface
, ~surface
->map_binding
);
3036 switch (surface
->map_binding
)
3038 case WINED3D_LOCATION_SYSMEM
:
3039 base_memory
= surface
->resource
.heap_memory
;
3042 case WINED3D_LOCATION_USER_MEMORY
:
3043 base_memory
= surface
->user_memory
;
3046 case WINED3D_LOCATION_DIB
:
3047 base_memory
= surface
->dib
.bitmap_data
;
3050 case WINED3D_LOCATION_BUFFER
:
3051 context
= context_acquire(device
, NULL
);
3052 gl_info
= context
->gl_info
;
3054 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
3055 base_memory
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
3056 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
3057 checkGLcall("map PBO");
3059 context_release(context
);
3063 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->map_binding
));
3067 if (format
->flags
& WINED3DFMT_FLAG_BROKEN_PITCH
)
3068 map_desc
->row_pitch
= surface
->resource
.width
* format
->byte_count
;
3070 map_desc
->row_pitch
= wined3d_surface_get_pitch(surface
);
3071 map_desc
->slice_pitch
= 0;
3075 map_desc
->data
= base_memory
;
3076 surface
->lockedRect
.left
= 0;
3077 surface
->lockedRect
.top
= 0;
3078 surface
->lockedRect
.right
= surface
->resource
.width
;
3079 surface
->lockedRect
.bottom
= surface
->resource
.height
;
3083 if ((format
->flags
& (WINED3DFMT_FLAG_BLOCKS
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_BLOCKS
)
3085 /* Compressed textures are block based, so calculate the offset of
3086 * the block that contains the top-left pixel of the locked rectangle. */
3087 map_desc
->data
= base_memory
3088 + ((rect
->top
/ format
->block_height
) * map_desc
->row_pitch
)
3089 + ((rect
->left
/ format
->block_width
) * format
->block_byte_count
);
3093 map_desc
->data
= base_memory
3094 + (map_desc
->row_pitch
* rect
->top
)
3095 + (rect
->left
* format
->byte_count
);
3097 surface
->lockedRect
.left
= rect
->left
;
3098 surface
->lockedRect
.top
= rect
->top
;
3099 surface
->lockedRect
.right
= rect
->right
;
3100 surface
->lockedRect
.bottom
= rect
->bottom
;
3103 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
3104 TRACE("Returning memory %p, pitch %u.\n", map_desc
->data
, map_desc
->row_pitch
);
3109 HRESULT CDECL
wined3d_surface_getdc(struct wined3d_surface
*surface
, HDC
*dc
)
3113 TRACE("surface %p, dc %p.\n", surface
, dc
);
3115 /* Give more detailed info for ddraw. */
3116 if (surface
->flags
& SFLAG_DCINUSE
)
3117 return WINEDDERR_DCALREADYCREATED
;
3119 /* Can't GetDC if the surface is locked. */
3120 if (surface
->resource
.map_count
)
3121 return WINED3DERR_INVALIDCALL
;
3123 /* Create a DIB section if there isn't a dc yet. */
3126 if (surface
->flags
& SFLAG_CLIENT
)
3128 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
3129 surface_release_client_storage(surface
);
3131 hr
= surface_create_dib_section(surface
);
3133 return WINED3DERR_INVALIDCALL
;
3134 if (!(surface
->map_binding
== WINED3D_LOCATION_USER_MEMORY
3135 || surface
->flags
& SFLAG_PIN_SYSMEM
3137 surface
->map_binding
= WINED3D_LOCATION_DIB
;
3140 surface_load_location(surface
, WINED3D_LOCATION_DIB
);
3141 surface_invalidate_location(surface
, ~WINED3D_LOCATION_DIB
);
3143 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3144 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
3146 /* GetDC on palettized formats is unsupported in D3D9, and the method
3147 * is missing in D3D8, so this should only be used for DX <=7
3148 * surfaces (with non-device palettes). */
3149 const RGBQUAD
*colors
= NULL
;
3151 if (surface
->palette
)
3153 colors
= surface
->palette
->colors
;
3157 struct wined3d_swapchain
*swapchain
= surface
->resource
.device
->swapchains
[0];
3158 struct wined3d_surface
*dds_primary
= swapchain
->front_buffer
;
3160 if (dds_primary
&& dds_primary
->palette
)
3161 colors
= dds_primary
->palette
->colors
;
3165 SetDIBColorTable(surface
->hDC
, 0, 256, colors
);
3168 surface
->flags
|= SFLAG_DCINUSE
;
3169 surface
->resource
.map_count
++;
3172 TRACE("Returning dc %p.\n", *dc
);
3177 HRESULT CDECL
wined3d_surface_releasedc(struct wined3d_surface
*surface
, HDC dc
)
3179 TRACE("surface %p, dc %p.\n", surface
, dc
);
3181 if (!(surface
->flags
& SFLAG_DCINUSE
))
3182 return WINEDDERR_NODC
;
3184 if (surface
->hDC
!= dc
)
3186 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
3188 return WINEDDERR_NODC
;
3191 surface
->resource
.map_count
--;
3192 surface
->flags
&= ~SFLAG_DCINUSE
;
3194 if (surface
->map_binding
== WINED3D_LOCATION_USER_MEMORY
|| (surface
->flags
& SFLAG_PIN_SYSMEM
3195 && surface
->map_binding
!= WINED3D_LOCATION_DIB
))
3197 /* The game Salammbo modifies the surface contents without mapping the surface between
3198 * a GetDC/ReleaseDC operation and flipping the surface. If the DIB remains the active
3199 * copy and is copied to the screen, this update, which draws the mouse pointer, is lost.
3200 * Do not only copy the DIB to the map location, but also make sure the map location is
3201 * copied back to the DIB in the next getdc call.
3203 * The same consideration applies to user memory surfaces. */
3204 surface_load_location(surface
, surface
->map_binding
);
3205 surface_invalidate_location(surface
, WINED3D_LOCATION_DIB
);
3211 static void read_from_framebuffer(struct wined3d_surface
*surface
, DWORD dst_location
)
3213 struct wined3d_device
*device
= surface
->resource
.device
;
3214 const struct wined3d_gl_info
*gl_info
;
3215 struct wined3d_context
*context
;
3219 BYTE
*row
, *top
, *bottom
;
3221 BOOL srcIsUpsideDown
;
3222 struct wined3d_bo_address data
;
3224 surface_get_memory(surface
, &data
, dst_location
);
3226 context
= context_acquire(device
, surface
);
3227 context_apply_blit_state(context
, device
);
3228 gl_info
= context
->gl_info
;
3230 /* Select the correct read buffer, and give some debug output.
3231 * There is no need to keep track of the current read buffer or reset it, every part of the code
3232 * that reads sets the read buffer as desired.
3234 if (surface_is_offscreen(surface
))
3236 /* Mapping the primary render target which is not on a swapchain.
3237 * Read from the back buffer. */
3238 TRACE("Mapping offscreen render target.\n");
3239 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3240 srcIsUpsideDown
= TRUE
;
3244 /* Onscreen surfaces are always part of a swapchain */
3245 GLenum buffer
= surface_get_gl_buffer(surface
);
3246 TRACE("Mapping %#x buffer.\n", buffer
);
3247 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
3248 checkGLcall("glReadBuffer");
3249 srcIsUpsideDown
= FALSE
;
3252 switch (surface
->resource
.format
->id
)
3254 case WINED3DFMT_P8_UINT
:
3256 type
= GL_UNSIGNED_BYTE
;
3260 fmt
= surface
->resource
.format
->glFormat
;
3261 type
= surface
->resource
.format
->glType
;
3264 if (data
.buffer_object
)
3266 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
3267 checkGLcall("glBindBufferARB");
3270 /* Setup pixel store pack state -- to glReadPixels into the correct place */
3271 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, surface
->resource
.width
);
3272 checkGLcall("glPixelStorei");
3274 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0,
3275 surface
->resource
.width
, surface
->resource
.height
,
3276 fmt
, type
, data
.addr
);
3277 checkGLcall("glReadPixels");
3279 /* Reset previous pixel store pack state */
3280 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
3281 checkGLcall("glPixelStorei");
3283 if (!srcIsUpsideDown
)
3285 /* glReadPixels returns the image upside down, and there is no way to prevent this.
3286 * Flip the lines in software. */
3287 UINT pitch
= wined3d_surface_get_pitch(surface
);
3289 if (!(row
= HeapAlloc(GetProcessHeap(), 0, pitch
)))
3292 if (data
.buffer_object
)
3294 mem
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
3295 checkGLcall("glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB)");
3301 bottom
= mem
+ pitch
* (surface
->resource
.height
- 1);
3302 for (i
= 0; i
< surface
->resource
.height
/ 2; i
++)
3304 memcpy(row
, top
, pitch
);
3305 memcpy(top
, bottom
, pitch
);
3306 memcpy(bottom
, row
, pitch
);
3310 HeapFree(GetProcessHeap(), 0, row
);
3312 if (data
.buffer_object
)
3313 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB
));
3317 if (data
.buffer_object
)
3319 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
3320 checkGLcall("glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)");
3323 context_release(context
);
3326 /* Read the framebuffer contents into a texture. Note that this function
3327 * doesn't do any kind of flipping. Using this on an onscreen surface will
3328 * result in a flipped D3D texture. */
3329 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
)
3331 struct wined3d_device
*device
= surface
->resource
.device
;
3332 const struct wined3d_gl_info
*gl_info
;
3333 struct wined3d_context
*context
;
3335 context
= context_acquire(device
, surface
);
3336 gl_info
= context
->gl_info
;
3337 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
3339 surface_prepare_texture(surface
, context
, srgb
);
3340 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
3342 TRACE("Reading back offscreen render target %p.\n", surface
);
3344 if (surface_is_offscreen(surface
))
3345 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3347 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(surface
));
3348 checkGLcall("glReadBuffer");
3350 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
3351 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
3352 checkGLcall("glCopyTexSubImage2D");
3354 context_release(context
);
3357 /* Context activation is done by the caller. */
3358 static void surface_prepare_texture_internal(struct wined3d_surface
*surface
,
3359 struct wined3d_context
*context
, BOOL srgb
)
3361 DWORD alloc_flag
= srgb
? SFLAG_SRGBALLOCATED
: SFLAG_ALLOCATED
;
3362 enum wined3d_conversion_type convert
;
3363 struct wined3d_format format
;
3365 if (surface
->flags
& alloc_flag
) return;
3367 d3dfmt_get_conv(surface
, TRUE
, TRUE
, &format
, &convert
);
3368 if (convert
!= WINED3D_CT_NONE
|| format
.convert
)
3369 surface
->flags
|= SFLAG_CONVERTED
;
3370 else surface
->flags
&= ~SFLAG_CONVERTED
;
3372 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
3373 surface_allocate_surface(surface
, context
->gl_info
, &format
, srgb
);
3374 surface
->flags
|= alloc_flag
;
3377 /* Context activation is done by the caller. */
3378 void surface_prepare_texture(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
3380 struct wined3d_texture
*texture
= surface
->container
;
3381 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
3384 TRACE("surface %p is a subresource of texture %p.\n", surface
, texture
);
3386 for (i
= 0; i
< sub_count
; ++i
)
3388 struct wined3d_surface
*s
= surface_from_resource(texture
->sub_resources
[i
]);
3389 surface_prepare_texture_internal(s
, context
, srgb
);
3395 void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
3399 if (surface
->rb_multisample
)
3402 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
3403 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
3404 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, surface
->resource
.multisample_type
,
3405 surface
->resource
.format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
3406 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
3410 if (surface
->rb_resolved
)
3413 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
3414 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
3415 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, surface
->resource
.format
->glInternal
,
3416 surface
->pow2Width
, surface
->pow2Height
);
3417 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
3421 static BOOL
color_in_range(const struct wined3d_color_key
*color_key
, DWORD color
)
3423 /* FIXME: Is this really how color keys are supposed to work? I think it
3424 * makes more sense to compare the individual channels. */
3425 return color
>= color_key
->color_space_low_value
3426 && color
<= color_key
->color_space_high_value
;
3429 void d3dfmt_p8_init_palette(const struct wined3d_surface
*surface
, BYTE table
[256][4], BOOL colorkey
)
3431 const struct wined3d_palette
*pal
= surface
->palette
;
3436 FIXME("No palette set.\n");
3437 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
3438 * there's no palette at this time. */
3439 for (i
= 0; i
< 256; i
++) table
[i
][3] = i
;
3443 TRACE("Using surface palette %p\n", pal
);
3444 for (i
= 0; i
< 256; ++i
)
3446 table
[i
][0] = pal
->colors
[i
].rgbRed
;
3447 table
[i
][1] = pal
->colors
[i
].rgbGreen
;
3448 table
[i
][2] = pal
->colors
[i
].rgbBlue
;
3449 /* The palette index is stored in the alpha component. In case of a
3450 * readback we can then read GL_ALPHA. Color keying is handled in
3451 * surface_blt_to_drawable() using a GL_ALPHA_TEST using GL_NOT_EQUAL.
3452 * In case of a P8 surface the color key itself is passed to
3453 * glAlphaFunc in other cases the alpha component of pixels that
3454 * should be masked away is set to 0. */
3460 static HRESULT
d3dfmt_convert_surface(const BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
, UINT height
,
3461 UINT outpitch
, enum wined3d_conversion_type conversion_type
, struct wined3d_surface
*surface
)
3466 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
3467 src
, dst
, pitch
, width
, height
, outpitch
, conversion_type
, surface
);
3469 switch (conversion_type
)
3471 case WINED3D_CT_NONE
:
3473 memcpy(dst
, src
, pitch
* height
);
3477 case WINED3D_CT_PALETTED
:
3478 case WINED3D_CT_PALETTED_CK
:
3483 d3dfmt_p8_init_palette(surface
, table
, (conversion_type
== WINED3D_CT_PALETTED_CK
));
3485 for (y
= 0; y
< height
; y
++)
3487 source
= src
+ pitch
* y
;
3488 dest
= dst
+ outpitch
* y
;
3489 /* This is an 1 bpp format, using the width here is fine */
3490 for (x
= 0; x
< width
; x
++) {
3491 BYTE color
= *source
++;
3492 *dest
++ = table
[color
][0];
3493 *dest
++ = table
[color
][1];
3494 *dest
++ = table
[color
][2];
3495 *dest
++ = table
[color
][3];
3501 case WINED3D_CT_CK_565
:
3503 /* Converting the 565 format in 5551 packed to emulate color-keying.
3505 Note : in all these conversion, it would be best to average the averaging
3506 pixels to get the color of the pixel that will be color-keyed to
3507 prevent 'color bleeding'. This will be done later on if ever it is
3510 Note2: Nvidia documents say that their driver does not support alpha + color keying
3511 on the same surface and disables color keying in such a case
3517 TRACE("Color keyed 565\n");
3519 for (y
= 0; y
< height
; y
++) {
3520 Source
= (const WORD
*)(src
+ y
* pitch
);
3521 Dest
= (WORD
*) (dst
+ y
* outpitch
);
3522 for (x
= 0; x
< width
; x
++ ) {
3523 WORD color
= *Source
++;
3524 *Dest
= ((color
& 0xffc0) | ((color
& 0x1f) << 1));
3525 if (!color_in_range(&surface
->container
->src_blt_color_key
, color
))
3533 case WINED3D_CT_CK_5551
:
3535 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
3539 TRACE("Color keyed 5551\n");
3540 for (y
= 0; y
< height
; y
++) {
3541 Source
= (const WORD
*)(src
+ y
* pitch
);
3542 Dest
= (WORD
*) (dst
+ y
* outpitch
);
3543 for (x
= 0; x
< width
; x
++ ) {
3544 WORD color
= *Source
++;
3546 if (!color_in_range(&surface
->container
->src_blt_color_key
, color
))
3549 *Dest
&= ~(1 << 15);
3556 case WINED3D_CT_CK_RGB24
:
3558 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
3560 for (y
= 0; y
< height
; y
++)
3562 source
= src
+ pitch
* y
;
3563 dest
= dst
+ outpitch
* y
;
3564 for (x
= 0; x
< width
; x
++) {
3565 DWORD color
= ((DWORD
)source
[0] << 16) + ((DWORD
)source
[1] << 8) + (DWORD
)source
[2] ;
3566 DWORD dstcolor
= color
<< 8;
3567 if (!color_in_range(&surface
->container
->src_blt_color_key
, color
))
3569 *(DWORD
*)dest
= dstcolor
;
3577 case WINED3D_CT_RGB32_888
:
3579 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
3581 for (y
= 0; y
< height
; y
++)
3583 source
= src
+ pitch
* y
;
3584 dest
= dst
+ outpitch
* y
;
3585 for (x
= 0; x
< width
; x
++) {
3586 DWORD color
= 0xffffff & *(const DWORD
*)source
;
3587 DWORD dstcolor
= color
<< 8;
3588 if (!color_in_range(&surface
->container
->src_blt_color_key
, color
))
3590 *(DWORD
*)dest
= dstcolor
;
3598 case WINED3D_CT_CK_ARGB32
:
3601 for (y
= 0; y
< height
; ++y
)
3603 source
= src
+ pitch
* y
;
3604 dest
= dst
+ outpitch
* y
;
3605 for (x
= 0; x
< width
; ++x
)
3607 DWORD color
= *(const DWORD
*)source
;
3608 if (color_in_range(&surface
->container
->src_blt_color_key
, color
))
3609 color
&= ~0xff000000;
3610 *(DWORD
*)dest
= color
;
3619 ERR("Unsupported conversion type %#x.\n", conversion_type
);
3624 void flip_surface(struct wined3d_surface
*front
, struct wined3d_surface
*back
)
3626 if (front
->container
->level_count
!= 1 || front
->container
->layer_count
!= 1
3627 || back
->container
->level_count
!= 1 || back
->container
->layer_count
!= 1)
3628 ERR("Flip between surfaces %p and %p not supported.\n", front
, back
);
3630 /* Flip the surface contents */
3635 front
->hDC
= back
->hDC
;
3639 /* Flip the DIBsection */
3641 HBITMAP tmp
= front
->dib
.DIBsection
;
3642 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
3643 back
->dib
.DIBsection
= tmp
;
3646 /* Flip the surface data */
3650 tmp
= front
->dib
.bitmap_data
;
3651 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
3652 back
->dib
.bitmap_data
= tmp
;
3654 tmp
= front
->resource
.heap_memory
;
3655 front
->resource
.heap_memory
= back
->resource
.heap_memory
;
3656 back
->resource
.heap_memory
= tmp
;
3661 GLuint tmp_pbo
= front
->pbo
;
3662 front
->pbo
= back
->pbo
;
3663 back
->pbo
= tmp_pbo
;
3666 /* Flip the opengl texture */
3670 tmp
= back
->container
->texture_rgb
.name
;
3671 back
->container
->texture_rgb
.name
= front
->container
->texture_rgb
.name
;
3672 front
->container
->texture_rgb
.name
= tmp
;
3674 tmp
= back
->container
->texture_srgb
.name
;
3675 back
->container
->texture_srgb
.name
= front
->container
->texture_srgb
.name
;
3676 front
->container
->texture_srgb
.name
= tmp
;
3678 tmp
= back
->rb_multisample
;
3679 back
->rb_multisample
= front
->rb_multisample
;
3680 front
->rb_multisample
= tmp
;
3682 tmp
= back
->rb_resolved
;
3683 back
->rb_resolved
= front
->rb_resolved
;
3684 front
->rb_resolved
= tmp
;
3686 resource_unload(&back
->resource
);
3687 resource_unload(&front
->resource
);
3691 DWORD tmp_flags
= back
->flags
;
3692 back
->flags
= front
->flags
;
3693 front
->flags
= tmp_flags
;
3695 tmp_flags
= back
->locations
;
3696 back
->locations
= front
->locations
;
3697 front
->locations
= tmp_flags
;
3701 /* Does a direct frame buffer -> texture copy. Stretching is done with single
3702 * pixel copy calls. */
3703 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3704 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3706 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3707 const struct wined3d_gl_info
*gl_info
;
3709 struct wined3d_context
*context
;
3710 BOOL upsidedown
= FALSE
;
3711 RECT dst_rect
= *dst_rect_in
;
3713 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3714 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3716 if(dst_rect
.top
> dst_rect
.bottom
) {
3717 UINT tmp
= dst_rect
.bottom
;
3718 dst_rect
.bottom
= dst_rect
.top
;
3723 context
= context_acquire(device
, src_surface
);
3724 gl_info
= context
->gl_info
;
3725 context_apply_blit_state(context
, device
);
3726 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3728 /* Bind the target texture */
3729 context_bind_texture(context
, dst_surface
->container
->target
, dst_surface
->container
->texture_rgb
.name
);
3730 if (surface_is_offscreen(src_surface
))
3732 TRACE("Reading from an offscreen target\n");
3733 upsidedown
= !upsidedown
;
3734 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3738 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3740 checkGLcall("glReadBuffer");
3742 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
3743 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
3745 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3747 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3749 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3750 ERR("Texture filtering not supported in direct blit.\n");
3752 else if ((filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3753 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3755 ERR("Texture filtering not supported in direct blit\n");
3759 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3760 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3762 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
3763 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3764 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
3765 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
3766 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3771 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
3772 /* I have to process this row by row to swap the image,
3773 * otherwise it would be upside down, so stretching in y direction
3774 * doesn't cost extra time
3776 * However, stretching in x direction can be avoided if not necessary
3778 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
3779 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3781 /* Well, that stuff works, but it's very slow.
3782 * find a better way instead
3786 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
3788 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3789 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
3790 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
3795 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3796 dst_rect
.left
/* x offset */, row
/* y offset */,
3797 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
3801 checkGLcall("glCopyTexSubImage2D");
3803 context_release(context
);
3805 /* The texture is now most up to date - If the surface is a render target
3806 * and has a drawable, this path is never entered. */
3807 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3808 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3811 /* Uses the hardware to stretch and flip the image */
3812 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3813 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3815 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3816 GLuint src
, backup
= 0;
3817 float left
, right
, top
, bottom
; /* Texture coordinates */
3818 UINT fbwidth
= src_surface
->resource
.width
;
3819 UINT fbheight
= src_surface
->resource
.height
;
3820 const struct wined3d_gl_info
*gl_info
;
3821 struct wined3d_context
*context
;
3822 GLenum drawBuffer
= GL_BACK
;
3823 GLenum texture_target
;
3824 BOOL noBackBufferBackup
;
3826 BOOL upsidedown
= FALSE
;
3827 RECT dst_rect
= *dst_rect_in
;
3829 TRACE("Using hwstretch blit\n");
3830 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3831 context
= context_acquire(device
, src_surface
);
3832 gl_info
= context
->gl_info
;
3833 context_apply_blit_state(context
, device
);
3834 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3836 src_offscreen
= surface_is_offscreen(src_surface
);
3837 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
3838 if (!noBackBufferBackup
&& !src_surface
->container
->texture_rgb
.name
)
3840 /* Get it a description */
3841 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3844 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3845 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3847 if (context
->aux_buffers
>= 2)
3849 /* Got more than one aux buffer? Use the 2nd aux buffer */
3850 drawBuffer
= GL_AUX1
;
3852 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
3854 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3855 drawBuffer
= GL_AUX0
;
3858 if (noBackBufferBackup
)
3860 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &backup
);
3861 checkGLcall("glGenTextures");
3862 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3863 texture_target
= GL_TEXTURE_2D
;
3867 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3868 * we are reading from the back buffer, the backup can be used as source texture
3870 texture_target
= src_surface
->texture_target
;
3871 context_bind_texture(context
, texture_target
, src_surface
->container
->texture_rgb
.name
);
3872 gl_info
->gl_ops
.gl
.p_glEnable(texture_target
);
3873 checkGLcall("glEnable(texture_target)");
3875 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3876 src_surface
->locations
&= ~WINED3D_LOCATION_TEXTURE_RGB
;
3879 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3880 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3882 if(dst_rect
.top
> dst_rect
.bottom
) {
3883 UINT tmp
= dst_rect
.bottom
;
3884 dst_rect
.bottom
= dst_rect
.top
;
3891 TRACE("Reading from an offscreen target\n");
3892 upsidedown
= !upsidedown
;
3893 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3897 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3900 /* TODO: Only back up the part that will be overwritten */
3901 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3903 checkGLcall("glCopyTexSubImage2D");
3905 /* No issue with overriding these - the sampler is dirty due to blit usage */
3906 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
,
3907 wined3d_gl_mag_filter(magLookup
, filter
));
3908 checkGLcall("glTexParameteri");
3909 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
3910 wined3d_gl_min_mip_filter(minMipLookup
, filter
, WINED3D_TEXF_NONE
));
3911 checkGLcall("glTexParameteri");
3913 if (!src_surface
->swapchain
|| src_surface
== src_surface
->swapchain
->back_buffers
[0])
3915 src
= backup
? backup
: src_surface
->container
->texture_rgb
.name
;
3919 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_FRONT
);
3920 checkGLcall("glReadBuffer(GL_FRONT)");
3922 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &src
);
3923 checkGLcall("glGenTextures(1, &src)");
3924 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
3926 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3927 * out for power of 2 sizes
3929 gl_info
->gl_ops
.gl
.p_glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
3930 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
3931 checkGLcall("glTexImage2D");
3932 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3934 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
3935 checkGLcall("glTexParameteri");
3936 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
3937 checkGLcall("glTexParameteri");
3939 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_BACK
);
3940 checkGLcall("glReadBuffer(GL_BACK)");
3942 if (texture_target
!= GL_TEXTURE_2D
)
3944 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3945 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3946 texture_target
= GL_TEXTURE_2D
;
3949 checkGLcall("glEnd and previous");
3951 left
= src_rect
->left
;
3952 right
= src_rect
->right
;
3956 top
= src_surface
->resource
.height
- src_rect
->top
;
3957 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
3961 top
= src_surface
->resource
.height
- src_rect
->bottom
;
3962 bottom
= src_surface
->resource
.height
- src_rect
->top
;
3965 if (src_surface
->flags
& SFLAG_NORMCOORD
)
3967 left
/= src_surface
->pow2Width
;
3968 right
/= src_surface
->pow2Width
;
3969 top
/= src_surface
->pow2Height
;
3970 bottom
/= src_surface
->pow2Height
;
3973 /* draw the source texture stretched and upside down. The correct surface is bound already */
3974 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
3975 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
3977 context_set_draw_buffer(context
, drawBuffer
);
3978 gl_info
->gl_ops
.gl
.p_glReadBuffer(drawBuffer
);
3980 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3982 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, bottom
);
3983 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3986 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, top
);
3987 gl_info
->gl_ops
.gl
.p_glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
3990 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, top
);
3991 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3994 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, bottom
);
3995 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
3996 gl_info
->gl_ops
.gl
.p_glEnd();
3997 checkGLcall("glEnd and previous");
3999 if (texture_target
!= dst_surface
->texture_target
)
4001 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
4002 gl_info
->gl_ops
.gl
.p_glEnable(dst_surface
->texture_target
);
4003 texture_target
= dst_surface
->texture_target
;
4006 /* Now read the stretched and upside down image into the destination texture */
4007 context_bind_texture(context
, texture_target
, dst_surface
->container
->texture_rgb
.name
);
4008 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
,
4010 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
4011 0, 0, /* We blitted the image to the origin */
4012 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
4013 checkGLcall("glCopyTexSubImage2D");
4015 if (drawBuffer
== GL_BACK
)
4017 /* Write the back buffer backup back. */
4020 if (texture_target
!= GL_TEXTURE_2D
)
4022 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
4023 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
4024 texture_target
= GL_TEXTURE_2D
;
4026 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
4030 if (texture_target
!= src_surface
->texture_target
)
4032 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
4033 gl_info
->gl_ops
.gl
.p_glEnable(src_surface
->texture_target
);
4034 texture_target
= src_surface
->texture_target
;
4036 context_bind_texture(context
, src_surface
->texture_target
, src_surface
->container
->texture_rgb
.name
);
4039 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
4041 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, 0.0f
);
4042 gl_info
->gl_ops
.gl
.p_glVertex2i(0, fbheight
);
4045 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
4046 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
4049 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
4050 (float)fbheight
/ (float)src_surface
->pow2Height
);
4051 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, 0);
4054 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
4055 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, fbheight
);
4056 gl_info
->gl_ops
.gl
.p_glEnd();
4058 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
4059 checkGLcall("glDisable(texture_target)");
4062 if (src
!= src_surface
->container
->texture_rgb
.name
&& src
!= backup
)
4064 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &src
);
4065 checkGLcall("glDeleteTextures(1, &src)");
4069 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &backup
);
4070 checkGLcall("glDeleteTextures(1, &backup)");
4073 if (wined3d_settings
.strict_draw_ordering
)
4074 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4076 context_release(context
);
4078 /* The texture is now most up to date - If the surface is a render target
4079 * and has a drawable, this path is never entered. */
4080 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4081 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
4084 /* Front buffer coordinates are always full screen coordinates, but our GL
4085 * drawable is limited to the window's client area. The sysmem and texture
4086 * copies do have the full screen size. Note that GL has a bottom-left
4087 * origin, while D3D has a top-left origin. */
4088 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
4090 UINT drawable_height
;
4092 if (surface
->swapchain
&& surface
== surface
->swapchain
->front_buffer
)
4094 POINT offset
= {0, 0};
4097 ScreenToClient(window
, &offset
);
4098 OffsetRect(rect
, offset
.x
, offset
.y
);
4100 GetClientRect(window
, &windowsize
);
4101 drawable_height
= windowsize
.bottom
- windowsize
.top
;
4105 drawable_height
= surface
->resource
.height
;
4108 rect
->top
= drawable_height
- rect
->top
;
4109 rect
->bottom
= drawable_height
- rect
->bottom
;
4112 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
4113 enum wined3d_texture_filter_type filter
, BOOL alpha_test
,
4114 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
4115 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
4117 const struct wined3d_gl_info
*gl_info
;
4118 struct wined3d_context
*context
;
4119 RECT src_rect
, dst_rect
;
4121 src_rect
= *src_rect_in
;
4122 dst_rect
= *dst_rect_in
;
4124 context
= context_acquire(device
, dst_surface
);
4125 gl_info
= context
->gl_info
;
4127 /* Make sure the surface is up-to-date. This should probably use
4128 * surface_load_location() and worry about the destination surface too,
4129 * unless we're overwriting it completely. */
4130 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
4132 /* Activate the destination context, set it up for blitting */
4133 context_apply_blit_state(context
, device
);
4135 if (!surface_is_offscreen(dst_surface
))
4136 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
4138 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
);
4142 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
4143 checkGLcall("glEnable(GL_ALPHA_TEST)");
4145 /* For P8 surfaces, the alpha component contains the palette index.
4146 * Which means that the colorkey is one of the palette entries. In
4147 * other cases pixels that should be masked away have alpha set to 0. */
4148 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
4149 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
,
4150 (float)src_surface
->container
->src_blt_color_key
.color_space_low_value
/ 256.0f
);
4152 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
4153 checkGLcall("glAlphaFunc");
4157 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
4158 checkGLcall("glDisable(GL_ALPHA_TEST)");
4161 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
4165 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
4166 checkGLcall("glDisable(GL_ALPHA_TEST)");
4169 /* Leave the opengl state valid for blitting */
4170 device
->blitter
->unset_shader(context
->gl_info
);
4172 if (wined3d_settings
.strict_draw_ordering
4173 || (dst_surface
->swapchain
&& dst_surface
->swapchain
->front_buffer
== dst_surface
))
4174 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4176 context_release(context
);
4179 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
4181 struct wined3d_device
*device
= s
->resource
.device
;
4182 const struct blit_shader
*blitter
;
4184 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_FILL
,
4185 NULL
, 0, 0, NULL
, rect
, s
->resource
.usage
, s
->resource
.pool
, s
->resource
.format
);
4188 FIXME("No blitter is capable of performing the requested color fill operation.\n");
4189 return WINED3DERR_INVALIDCALL
;
4192 return blitter
->color_fill(device
, s
, rect
, color
);
4195 static HRESULT
surface_blt_special(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
4196 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
,
4197 enum wined3d_texture_filter_type filter
)
4199 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4200 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4201 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
4203 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
4204 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
4205 flags
, DDBltFx
, debug_d3dtexturefiltertype(filter
));
4207 /* Get the swapchain. One of the surfaces has to be a primary surface */
4208 if (dst_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
4210 WARN("Destination is in sysmem, rejecting gl blt\n");
4211 return WINED3DERR_INVALIDCALL
;
4214 dst_swapchain
= dst_surface
->swapchain
;
4218 if (src_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
4220 WARN("Src is in sysmem, rejecting gl blt\n");
4221 return WINED3DERR_INVALIDCALL
;
4224 src_swapchain
= src_surface
->swapchain
;
4228 src_swapchain
= NULL
;
4231 /* Early sort out of cases where no render target is used */
4232 if (!dst_swapchain
&& !src_swapchain
4233 && src_surface
!= device
->fb
.render_targets
[0]
4234 && dst_surface
!= device
->fb
.render_targets
[0])
4236 TRACE("No surface is render target, not using hardware blit.\n");
4237 return WINED3DERR_INVALIDCALL
;
4240 /* No destination color keying supported */
4241 if (flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
))
4243 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
4244 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
4245 return WINED3DERR_INVALIDCALL
;
4248 if (dst_swapchain
&& dst_swapchain
== src_swapchain
)
4250 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
4251 return WINED3DERR_INVALIDCALL
;
4254 if (dst_swapchain
&& src_swapchain
)
4256 FIXME("Implement hardware blit between two different swapchains\n");
4257 return WINED3DERR_INVALIDCALL
;
4262 /* Handled with regular texture -> swapchain blit */
4263 if (src_surface
== device
->fb
.render_targets
[0])
4264 TRACE("Blit from active render target to a swapchain\n");
4266 else if (src_swapchain
&& dst_surface
== device
->fb
.render_targets
[0])
4268 FIXME("Implement blit from a swapchain to the active render target\n");
4269 return WINED3DERR_INVALIDCALL
;
4272 if ((src_swapchain
|| src_surface
== device
->fb
.render_targets
[0]) && !dst_swapchain
)
4274 /* Blit from render target to texture */
4277 /* P8 read back is not implemented */
4278 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
4279 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
4281 TRACE("P8 read back not supported by frame buffer to texture blit\n");
4282 return WINED3DERR_INVALIDCALL
;
4285 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
4287 TRACE("Color keying not supported by frame buffer to texture blit\n");
4288 return WINED3DERR_INVALIDCALL
;
4289 /* Destination color key is checked above */
4292 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
4297 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
4298 * flip the image nor scale it.
4300 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
4301 * -> If the app wants an image width an unscaled width, copy it line per line
4302 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
4303 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
4304 * back buffer. This is slower than reading line per line, thus not used for flipping
4305 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
4306 * pixel by pixel. */
4307 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
4308 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
4310 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
4311 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
4315 TRACE("Using hardware stretching to flip / stretch the texture.\n");
4316 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
4319 surface_evict_sysmem(dst_surface
);
4323 else if (src_surface
)
4325 /* Blit from offscreen surface to render target */
4326 struct wined3d_color_key old_blt_key
= src_surface
->container
->src_blt_color_key
;
4327 DWORD old_color_key_flags
= src_surface
->container
->color_key_flags
;
4329 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
4331 if (!device
->blitter
->blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4332 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
4333 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
4335 FIXME("Unsupported blit operation falling back to software\n");
4336 return WINED3DERR_INVALIDCALL
;
4339 /* Color keying: Check if we have to do a color keyed blt,
4340 * and if not check if a color key is activated.
4342 * Just modify the color keying parameters in the surface and restore them afterwards
4343 * The surface keeps track of the color key last used to load the opengl surface.
4344 * PreLoad will catch the change to the flags and color key and reload if necessary.
4346 if (flags
& WINEDDBLT_KEYSRC
)
4348 /* Use color key from surface */
4350 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
4352 /* Use color key from DDBltFx */
4353 src_surface
->container
->color_key_flags
|= WINEDDSD_CKSRCBLT
;
4354 src_surface
->container
->src_blt_color_key
= DDBltFx
->ddckSrcColorkey
;
4358 /* Do not use color key */
4359 src_surface
->container
->color_key_flags
&= ~WINEDDSD_CKSRCBLT
;
4362 surface_blt_to_drawable(device
, filter
,
4363 flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_ALPHATEST
),
4364 src_surface
, src_rect
, dst_surface
, dst_rect
);
4366 /* Restore the color key parameters */
4367 src_surface
->container
->color_key_flags
= old_color_key_flags
;
4368 src_surface
->container
->src_blt_color_key
= old_blt_key
;
4370 surface_validate_location(dst_surface
, dst_surface
->draw_binding
);
4371 surface_invalidate_location(dst_surface
, ~dst_surface
->draw_binding
);
4376 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
4377 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
4378 return WINED3DERR_INVALIDCALL
;
4381 /* Context activation is done by the caller. */
4382 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
4383 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
4385 struct wined3d_device
*device
= surface
->resource
.device
;
4386 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4387 GLint compare_mode
= GL_NONE
;
4388 struct blt_info info
;
4389 GLint old_binding
= 0;
4392 gl_info
->gl_ops
.gl
.p_glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
4394 gl_info
->gl_ops
.gl
.p_glDisable(GL_CULL_FACE
);
4395 gl_info
->gl_ops
.gl
.p_glDisable(GL_BLEND
);
4396 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
4397 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
4398 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST
);
4399 gl_info
->gl_ops
.gl
.p_glEnable(GL_DEPTH_TEST
);
4400 gl_info
->gl_ops
.gl
.p_glDepthFunc(GL_ALWAYS
);
4401 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
4402 gl_info
->gl_ops
.gl
.p_glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
4403 gl_info
->gl_ops
.gl
.p_glViewport(x
, y
, w
, h
);
4404 gl_info
->gl_ops
.gl
.p_glDepthRange(0.0, 1.0);
4406 SetRect(&rect
, 0, h
, w
, 0);
4407 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
4408 context_active_texture(context
, context
->gl_info
, 0);
4409 gl_info
->gl_ops
.gl
.p_glGetIntegerv(info
.binding
, &old_binding
);
4410 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, texture
);
4411 if (gl_info
->supported
[ARB_SHADOW
])
4413 gl_info
->gl_ops
.gl
.p_glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
4414 if (compare_mode
!= GL_NONE
)
4415 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
4418 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
4419 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
4421 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
4422 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
4423 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, -1.0f
);
4424 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
4425 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, -1.0f
);
4426 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
4427 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, 1.0f
);
4428 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
4429 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, 1.0f
);
4430 gl_info
->gl_ops
.gl
.p_glEnd();
4432 if (compare_mode
!= GL_NONE
)
4433 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
4434 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, old_binding
);
4436 gl_info
->gl_ops
.gl
.p_glPopAttrib();
4438 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
4441 void surface_modify_ds_location(struct wined3d_surface
*surface
,
4442 DWORD location
, UINT w
, UINT h
)
4444 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
4446 if (((surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && !(location
& WINED3D_LOCATION_TEXTURE_RGB
))
4447 || (!(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && (location
& WINED3D_LOCATION_TEXTURE_RGB
)))
4448 wined3d_texture_set_dirty(surface
->container
);
4450 surface
->ds_current_size
.cx
= w
;
4451 surface
->ds_current_size
.cy
= h
;
4452 surface
->locations
= location
;
4455 /* Context activation is done by the caller. */
4456 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
4458 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4459 struct wined3d_device
*device
= surface
->resource
.device
;
4462 TRACE("surface %p, new location %#x.\n", surface
, location
);
4464 /* TODO: Make this work for modes other than FBO */
4465 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
4467 if (!(surface
->locations
& location
))
4469 w
= surface
->ds_current_size
.cx
;
4470 h
= surface
->ds_current_size
.cy
;
4471 surface
->ds_current_size
.cx
= 0;
4472 surface
->ds_current_size
.cy
= 0;
4476 w
= surface
->resource
.width
;
4477 h
= surface
->resource
.height
;
4480 if (surface
->ds_current_size
.cx
== surface
->resource
.width
4481 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
4483 TRACE("Location (%#x) is already up to date.\n", location
);
4487 if (surface
->current_renderbuffer
)
4489 FIXME("Not supported with fixed up depth stencil.\n");
4493 if (surface
->locations
& WINED3D_LOCATION_DISCARDED
)
4495 TRACE("Surface was discarded, no need copy data.\n");
4498 case WINED3D_LOCATION_TEXTURE_RGB
:
4499 surface_prepare_texture(surface
, context
, FALSE
);
4501 case WINED3D_LOCATION_RB_MULTISAMPLE
:
4502 surface_prepare_rb(surface
, gl_info
, TRUE
);
4504 case WINED3D_LOCATION_DRAWABLE
:
4508 FIXME("Unhandled location %#x\n", location
);
4510 surface
->locations
&= ~WINED3D_LOCATION_DISCARDED
;
4511 surface
->locations
|= location
;
4512 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4513 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4517 if (!surface
->locations
)
4519 FIXME("No up to date depth stencil location.\n");
4520 surface
->locations
|= location
;
4521 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4522 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4526 if (location
== WINED3D_LOCATION_TEXTURE_RGB
)
4528 GLint old_binding
= 0;
4531 /* The render target is allowed to be smaller than the depth/stencil
4532 * buffer, so the onscreen depth/stencil buffer is potentially smaller
4533 * than the offscreen surface. Don't overwrite the offscreen surface
4534 * with undefined data. */
4535 w
= min(w
, context
->swapchain
->desc
.backbuffer_width
);
4536 h
= min(h
, context
->swapchain
->desc
.backbuffer_height
);
4538 TRACE("Copying onscreen depth buffer to depth texture.\n");
4540 if (!device
->depth_blt_texture
)
4541 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &device
->depth_blt_texture
);
4543 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4544 * directly on the FBO texture. That's because we need to flip. */
4545 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4546 context
->swapchain
->front_buffer
, NULL
, WINED3D_LOCATION_DRAWABLE
);
4547 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
4549 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
4550 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
4554 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
4555 bind_target
= GL_TEXTURE_2D
;
4557 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, device
->depth_blt_texture
);
4558 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
4559 * internal format, because the internal format might include stencil
4560 * data. In principle we should copy stencil data as well, but unless
4561 * the driver supports stencil export it's hard to do, and doesn't
4562 * seem to be needed in practice. If the hardware doesn't support
4563 * writing stencil data, the glCopyTexImage2D() call might trigger
4564 * software fallbacks. */
4565 gl_info
->gl_ops
.gl
.p_glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
4566 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
4567 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
4568 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
4569 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
4570 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
4571 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
4572 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, old_binding
);
4574 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4575 NULL
, surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4576 context_set_draw_buffer(context
, GL_NONE
);
4578 /* Do the actual blit */
4579 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
4580 checkGLcall("depth_blt");
4582 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
4584 if (wined3d_settings
.strict_draw_ordering
)
4585 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4587 else if (location
== WINED3D_LOCATION_DRAWABLE
)
4589 TRACE("Copying depth texture to onscreen depth buffer.\n");
4591 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4592 context
->swapchain
->front_buffer
, NULL
, WINED3D_LOCATION_DRAWABLE
);
4593 surface_depth_blt(surface
, context
, surface
->container
->texture_rgb
.name
,
4594 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
4595 checkGLcall("depth_blt");
4597 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
4599 if (wined3d_settings
.strict_draw_ordering
)
4600 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4604 ERR("Invalid location (%#x) specified.\n", location
);
4607 surface
->locations
|= location
;
4608 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4609 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4612 void surface_validate_location(struct wined3d_surface
*surface
, DWORD location
)
4614 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4616 surface
->locations
|= location
;
4619 void surface_invalidate_location(struct wined3d_surface
*surface
, DWORD location
)
4621 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4623 if (location
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4624 wined3d_texture_set_dirty(surface
->container
);
4625 surface
->locations
&= ~location
;
4627 if (!surface
->locations
)
4628 ERR("Surface %p does not have any up to date location.\n", surface
);
4631 static DWORD
resource_access_from_location(DWORD location
)
4635 case WINED3D_LOCATION_SYSMEM
:
4636 case WINED3D_LOCATION_USER_MEMORY
:
4637 case WINED3D_LOCATION_DIB
:
4638 case WINED3D_LOCATION_BUFFER
:
4639 return WINED3D_RESOURCE_ACCESS_CPU
;
4641 case WINED3D_LOCATION_DRAWABLE
:
4642 case WINED3D_LOCATION_TEXTURE_SRGB
:
4643 case WINED3D_LOCATION_TEXTURE_RGB
:
4644 case WINED3D_LOCATION_RB_MULTISAMPLE
:
4645 case WINED3D_LOCATION_RB_RESOLVED
:
4646 return WINED3D_RESOURCE_ACCESS_GPU
;
4649 FIXME("Unhandled location %#x.\n", location
);
4654 static void surface_copy_simple_location(struct wined3d_surface
*surface
, DWORD location
)
4656 struct wined3d_device
*device
= surface
->resource
.device
;
4657 struct wined3d_context
*context
;
4658 const struct wined3d_gl_info
*gl_info
;
4659 struct wined3d_bo_address dst
, src
;
4660 UINT size
= surface
->resource
.size
;
4662 surface_get_memory(surface
, &dst
, location
);
4663 surface_get_memory(surface
, &src
, surface
->locations
);
4665 if (dst
.buffer_object
)
4667 context
= context_acquire(device
, NULL
);
4668 gl_info
= context
->gl_info
;
4669 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, dst
.buffer_object
));
4670 GL_EXTCALL(glBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0, size
, src
.addr
));
4671 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4672 checkGLcall("Upload PBO");
4673 context_release(context
);
4676 if (src
.buffer_object
)
4678 context
= context_acquire(device
, NULL
);
4679 gl_info
= context
->gl_info
;
4680 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, src
.buffer_object
));
4681 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_PACK_BUFFER_ARB
, 0, size
, dst
.addr
));
4682 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
4683 checkGLcall("Download PBO");
4684 context_release(context
);
4687 memcpy(dst
.addr
, src
.addr
, size
);
4690 static void surface_load_sysmem(struct wined3d_surface
*surface
,
4691 const struct wined3d_gl_info
*gl_info
, DWORD dst_location
)
4693 if (surface
->locations
& surface_simple_locations
)
4695 surface_copy_simple_location(surface
, dst_location
);
4699 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
))
4700 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4702 /* Download the surface to system memory. */
4703 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4705 struct wined3d_device
*device
= surface
->resource
.device
;
4706 struct wined3d_context
*context
;
4708 /* TODO: Use already acquired context when possible. */
4709 context
= context_acquire(device
, NULL
);
4711 wined3d_texture_bind_and_dirtify(surface
->container
, context
,
4712 !(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
));
4713 surface_download_data(surface
, gl_info
, dst_location
);
4715 context_release(context
);
4720 if (surface
->locations
& WINED3D_LOCATION_DRAWABLE
)
4722 read_from_framebuffer(surface
, dst_location
);
4726 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
4727 surface
, wined3d_debug_location(surface
->locations
));
4730 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
4731 const struct wined3d_gl_info
*gl_info
)
4735 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& surface_is_offscreen(surface
))
4737 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
4738 return WINED3DERR_INVALIDCALL
;
4741 surface_get_rect(surface
, NULL
, &r
);
4742 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4743 surface_blt_to_drawable(surface
->resource
.device
,
4744 WINED3D_TEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
4749 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
4750 const struct wined3d_gl_info
*gl_info
, BOOL srgb
)
4752 RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4753 struct wined3d_device
*device
= surface
->resource
.device
;
4754 enum wined3d_conversion_type convert
;
4755 struct wined3d_context
*context
;
4756 UINT width
, src_pitch
, dst_pitch
;
4757 struct wined3d_bo_address data
;
4758 struct wined3d_format format
;
4759 POINT dst_point
= {0, 0};
4762 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
4763 && surface_is_offscreen(surface
)
4764 && (surface
->locations
& WINED3D_LOCATION_DRAWABLE
))
4766 surface_load_fb_texture(surface
, srgb
);
4771 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| WINED3D_LOCATION_TEXTURE_RGB
)
4772 && (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
4773 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4774 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4775 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4778 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_RGB
,
4779 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
, &src_rect
);
4781 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
,
4782 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_RGB
, &src_rect
);
4787 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
)
4788 && (!srgb
|| (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
4789 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4790 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4791 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4793 DWORD src_location
= surface
->locations
& WINED3D_LOCATION_RB_RESOLVED
?
4794 WINED3D_LOCATION_RB_RESOLVED
: WINED3D_LOCATION_RB_MULTISAMPLE
;
4795 DWORD dst_location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
4796 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4798 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, src_location
,
4799 &rect
, surface
, dst_location
, &rect
);
4804 /* Upload from system memory */
4806 d3dfmt_get_conv(surface
, TRUE
/* We need color keying */,
4807 TRUE
/* We will use textures */, &format
, &convert
);
4811 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| surface
->map_binding
))
4812 == WINED3D_LOCATION_TEXTURE_RGB
)
4814 /* Performance warning... */
4815 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
4816 surface_prepare_map_memory(surface
);
4817 surface_load_location(surface
, surface
->map_binding
);
4822 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| surface
->map_binding
))
4823 == WINED3D_LOCATION_TEXTURE_SRGB
)
4825 /* Performance warning... */
4826 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
4827 surface_prepare_map_memory(surface
);
4828 surface_load_location(surface
, surface
->map_binding
);
4832 if (!(surface
->locations
& surface_simple_locations
))
4834 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
4835 /* Lets hope we get it from somewhere... */
4836 surface_prepare_system_memory(surface
);
4837 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
4840 /* TODO: Use already acquired context when possible. */
4841 context
= context_acquire(device
, NULL
);
4843 surface_prepare_texture(surface
, context
, srgb
);
4844 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
4846 if (surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
)
4848 surface
->flags
|= SFLAG_GLCKEY
;
4849 surface
->gl_color_key
= surface
->container
->src_blt_color_key
;
4851 else surface
->flags
&= ~SFLAG_GLCKEY
;
4853 width
= surface
->resource
.width
;
4854 src_pitch
= wined3d_surface_get_pitch(surface
);
4856 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
4857 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
4859 if ((convert
!= WINED3D_CT_NONE
|| format
.convert
) && surface
->pbo
)
4861 TRACE("Removing the pbo attached to surface %p.\n", surface
);
4863 if (surface
->flags
& SFLAG_DIBSECTION
)
4864 surface
->map_binding
= WINED3D_LOCATION_DIB
;
4866 surface
->map_binding
= WINED3D_LOCATION_SYSMEM
;
4868 surface_prepare_map_memory(surface
);
4869 surface_load_location(surface
, surface
->map_binding
);
4870 surface_remove_pbo(surface
, gl_info
);
4873 surface_get_memory(surface
, &data
, surface
->locations
);
4876 /* This code is entered for texture formats which need a fixup. */
4877 UINT height
= surface
->resource
.height
;
4879 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4880 dst_pitch
= width
* format
.conv_byte_count
;
4881 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4883 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4885 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4886 context_release(context
);
4887 return E_OUTOFMEMORY
;
4889 format
.convert(data
.addr
, mem
, src_pitch
, src_pitch
* height
,
4890 dst_pitch
, dst_pitch
* height
, width
, height
, 1);
4891 format
.byte_count
= format
.conv_byte_count
;
4892 src_pitch
= dst_pitch
;
4895 else if (convert
!= WINED3D_CT_NONE
)
4897 /* This code is only entered for color keying fixups */
4898 UINT height
= surface
->resource
.height
;
4900 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4901 dst_pitch
= width
* format
.conv_byte_count
;
4902 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4904 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4906 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4907 context_release(context
);
4908 return E_OUTOFMEMORY
;
4910 d3dfmt_convert_surface(data
.addr
, mem
, src_pitch
,
4911 width
, height
, dst_pitch
, convert
, surface
);
4912 format
.byte_count
= format
.conv_byte_count
;
4913 src_pitch
= dst_pitch
;
4917 surface_upload_data(surface
, gl_info
, &format
, &src_rect
, src_pitch
, &dst_point
, srgb
, &data
);
4919 context_release(context
);
4921 HeapFree(GetProcessHeap(), 0, mem
);
4926 static void surface_multisample_resolve(struct wined3d_surface
*surface
)
4928 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4930 if (!(surface
->locations
& WINED3D_LOCATION_RB_MULTISAMPLE
))
4931 ERR("Trying to resolve multisampled surface %p, but location WINED3D_LOCATION_RB_MULTISAMPLE not current.\n",
4934 surface_blt_fbo(surface
->resource
.device
, WINED3D_TEXF_POINT
,
4935 surface
, WINED3D_LOCATION_RB_MULTISAMPLE
, &rect
, surface
, WINED3D_LOCATION_RB_RESOLVED
, &rect
);
4938 HRESULT
surface_load_location(struct wined3d_surface
*surface
, DWORD location
)
4940 struct wined3d_device
*device
= surface
->resource
.device
;
4941 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4944 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4946 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
4948 if (location
== WINED3D_LOCATION_TEXTURE_RGB
4949 && surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_DISCARDED
))
4951 struct wined3d_context
*context
= context_acquire(device
, NULL
);
4952 surface_load_ds_location(surface
, context
, location
);
4953 context_release(context
);
4956 else if (location
& surface
->locations
&& surface
->draw_binding
!= WINED3D_LOCATION_DRAWABLE
)
4958 /* Already up to date, nothing to do. */
4963 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
4964 wined3d_debug_location(surface
->locations
), wined3d_debug_location(location
));
4965 return WINED3DERR_INVALIDCALL
;
4969 if (surface
->locations
& location
)
4971 TRACE("Location already up to date.\n");
4975 if (WARN_ON(d3d_surface
))
4977 DWORD required_access
= resource_access_from_location(location
);
4978 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
4979 WARN("Operation requires %#x access, but surface only has %#x.\n",
4980 required_access
, surface
->resource
.access_flags
);
4983 if (!surface
->locations
)
4985 ERR("Surface %p does not have any up to date location.\n", surface
);
4986 surface
->flags
|= SFLAG_LOST
;
4987 return WINED3DERR_DEVICELOST
;
4992 case WINED3D_LOCATION_DIB
:
4993 case WINED3D_LOCATION_USER_MEMORY
:
4994 case WINED3D_LOCATION_SYSMEM
:
4995 case WINED3D_LOCATION_BUFFER
:
4996 surface_load_sysmem(surface
, gl_info
, location
);
4999 case WINED3D_LOCATION_DRAWABLE
:
5000 if (FAILED(hr
= surface_load_drawable(surface
, gl_info
)))
5004 case WINED3D_LOCATION_RB_RESOLVED
:
5005 surface_multisample_resolve(surface
);
5008 case WINED3D_LOCATION_TEXTURE_RGB
:
5009 case WINED3D_LOCATION_TEXTURE_SRGB
:
5010 if (FAILED(hr
= surface_load_texture(surface
, gl_info
, location
== WINED3D_LOCATION_TEXTURE_SRGB
)))
5015 ERR("Don't know how to handle location %#x.\n", location
);
5019 surface_validate_location(surface
, location
);
5021 if (location
!= WINED3D_LOCATION_SYSMEM
&& (surface
->locations
& WINED3D_LOCATION_SYSMEM
))
5022 surface_evict_sysmem(surface
);
5027 BOOL
surface_is_offscreen(const struct wined3d_surface
*surface
)
5029 struct wined3d_swapchain
*swapchain
;
5031 /* Not on a swapchain - must be offscreen */
5032 if (!(swapchain
= surface
->swapchain
))
5035 /* The front buffer is always onscreen */
5036 if (surface
== swapchain
->front_buffer
) return FALSE
;
5038 /* If the swapchain is rendered to an FBO, the backbuffer is
5039 * offscreen, otherwise onscreen */
5040 return swapchain
->render_to_fbo
;
5043 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
5044 /* Context activation is done by the caller. */
5045 static void ffp_blit_free(struct wined3d_device
*device
) { }
5047 /* Context activation is done by the caller. */
5048 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
5050 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
5052 gl_info
->gl_ops
.gl
.p_glEnable(surface
->container
->target
);
5053 checkGLcall("glEnable(target)");
5058 /* Context activation is done by the caller. */
5059 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
5061 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_2D
);
5062 checkGLcall("glDisable(GL_TEXTURE_2D)");
5063 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
5065 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
5066 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
5068 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
5070 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_RECTANGLE_ARB
);
5071 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
5075 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
5076 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
5077 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
5081 case WINED3D_BLIT_OP_COLOR_BLIT
:
5082 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
5085 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
5087 TRACE("Checking support for fixup:\n");
5088 dump_color_fixup_desc(src_format
->color_fixup
);
5091 /* We only support identity conversions. */
5092 if (!is_identity_fixup(src_format
->color_fixup
)
5093 || !is_identity_fixup(dst_format
->color_fixup
))
5095 TRACE("Fixups are not supported.\n");
5101 case WINED3D_BLIT_OP_COLOR_FILL
:
5102 if (dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
5105 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
5107 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
5110 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
5112 TRACE("Color fill not supported\n");
5116 /* FIXME: We should reject color fills on formats with fixups,
5117 * but this would break P8 color fills for example. */
5121 case WINED3D_BLIT_OP_DEPTH_FILL
:
5125 TRACE("Unsupported blit_op=%d\n", blit_op
);
5130 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
5131 const RECT
*dst_rect
, const struct wined3d_color
*color
)
5133 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
5134 struct wined3d_fb_state fb
= {&dst_surface
, NULL
};
5136 device_clear_render_targets(device
, 1, &fb
, 1, dst_rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
5141 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
,
5142 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
5144 const RECT draw_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
5145 struct wined3d_fb_state fb
= {NULL
, surface
};
5147 device_clear_render_targets(device
, 0, &fb
, 1, rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
5152 const struct blit_shader ffp_blit
= {
5158 ffp_blit_color_fill
,
5159 ffp_blit_depth_fill
,
5162 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
5167 /* Context activation is done by the caller. */
5168 static void cpu_blit_free(struct wined3d_device
*device
)
5172 /* Context activation is done by the caller. */
5173 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
5178 /* Context activation is done by the caller. */
5179 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
5183 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
5184 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
5185 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
5187 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
5195 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
5196 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
5197 const struct wined3d_format
*format
, DWORD flags
, const WINEDDBLTFX
*fx
)
5199 UINT row_block_count
;
5200 const BYTE
*src_row
;
5207 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
5211 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5213 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
5214 src_row
+= src_pitch
;
5215 dst_row
+= dst_pitch
;
5221 if (flags
== WINEDDBLT_DDFX
&& fx
->dwDDFX
== WINEDDBLTFX_MIRRORUPDOWN
)
5223 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
5227 case WINED3DFMT_DXT1
:
5228 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5233 BYTE control_row
[4];
5236 const struct block
*s
= (const struct block
*)src_row
;
5237 struct block
*d
= (struct block
*)dst_row
;
5239 for (x
= 0; x
< row_block_count
; ++x
)
5241 d
[x
].color
[0] = s
[x
].color
[0];
5242 d
[x
].color
[1] = s
[x
].color
[1];
5243 d
[x
].control_row
[0] = s
[x
].control_row
[3];
5244 d
[x
].control_row
[1] = s
[x
].control_row
[2];
5245 d
[x
].control_row
[2] = s
[x
].control_row
[1];
5246 d
[x
].control_row
[3] = s
[x
].control_row
[0];
5248 src_row
-= src_pitch
;
5249 dst_row
+= dst_pitch
;
5253 case WINED3DFMT_DXT2
:
5254 case WINED3DFMT_DXT3
:
5255 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5261 BYTE control_row
[4];
5264 const struct block
*s
= (const struct block
*)src_row
;
5265 struct block
*d
= (struct block
*)dst_row
;
5267 for (x
= 0; x
< row_block_count
; ++x
)
5269 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
5270 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
5271 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
5272 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
5273 d
[x
].color
[0] = s
[x
].color
[0];
5274 d
[x
].color
[1] = s
[x
].color
[1];
5275 d
[x
].control_row
[0] = s
[x
].control_row
[3];
5276 d
[x
].control_row
[1] = s
[x
].control_row
[2];
5277 d
[x
].control_row
[2] = s
[x
].control_row
[1];
5278 d
[x
].control_row
[3] = s
[x
].control_row
[0];
5280 src_row
-= src_pitch
;
5281 dst_row
+= dst_pitch
;
5286 FIXME("Compressed flip not implemented for format %s.\n",
5287 debug_d3dformat(format
->id
));
5292 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
5293 debug_d3dformat(format
->id
), flags
, flags
& WINEDDBLT_DDFX
? fx
->dwDDFX
: 0);
5298 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5299 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
5300 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
5302 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
5303 const struct wined3d_format
*src_format
, *dst_format
;
5304 struct wined3d_texture
*src_texture
= NULL
;
5305 struct wined3d_map_desc dst_map
, src_map
;
5306 const BYTE
*sbase
= NULL
;
5307 HRESULT hr
= WINED3D_OK
;
5312 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5313 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5314 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5316 if (src_surface
== dst_surface
)
5318 wined3d_surface_map(dst_surface
, &dst_map
, NULL
, 0);
5320 src_format
= dst_surface
->resource
.format
;
5321 dst_format
= src_format
;
5325 dst_format
= dst_surface
->resource
.format
;
5328 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
5330 if (!(src_texture
= surface_convert_format(src_surface
, dst_format
->id
)))
5332 /* The conv function writes a FIXME */
5333 WARN("Cannot convert source surface format to dest format.\n");
5336 src_surface
= surface_from_resource(wined3d_texture_get_sub_resource(src_texture
, 0));
5338 wined3d_surface_map(src_surface
, &src_map
, NULL
, WINED3D_MAP_READONLY
);
5339 src_format
= src_surface
->resource
.format
;
5343 src_format
= dst_format
;
5346 wined3d_surface_map(dst_surface
, &dst_map
, dst_rect
, 0);
5349 bpp
= dst_surface
->resource
.format
->byte_count
;
5350 srcheight
= src_rect
->bottom
- src_rect
->top
;
5351 srcwidth
= src_rect
->right
- src_rect
->left
;
5352 dstheight
= dst_rect
->bottom
- dst_rect
->top
;
5353 dstwidth
= dst_rect
->right
- dst_rect
->left
;
5354 width
= (dst_rect
->right
- dst_rect
->left
) * bpp
;
5357 sbase
= (BYTE
*)src_map
.data
5358 + ((src_rect
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
5359 + ((src_rect
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
5360 if (src_surface
!= dst_surface
)
5361 dbuf
= dst_map
.data
;
5363 dbuf
= (BYTE
*)dst_map
.data
5364 + ((dst_rect
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
5365 + ((dst_rect
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
5367 if (src_format
->flags
& dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
5369 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
5371 if (src_surface
== dst_surface
)
5373 FIXME("Only plain blits supported on compressed surfaces.\n");
5378 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
5380 WARN("Stretching not supported on compressed surfaces.\n");
5381 hr
= WINED3DERR_INVALIDCALL
;
5385 if (!surface_check_block_align(src_surface
, src_rect
))
5387 WARN("Source rectangle not block-aligned.\n");
5388 hr
= WINED3DERR_INVALIDCALL
;
5392 if (!surface_check_block_align(dst_surface
, dst_rect
))
5394 WARN("Destination rectangle not block-aligned.\n");
5395 hr
= WINED3DERR_INVALIDCALL
;
5399 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
5400 src_map
.row_pitch
, dst_map
.row_pitch
, dstwidth
, dstheight
,
5401 src_format
, flags
, fx
);
5405 /* First, all the 'source-less' blits */
5406 if (flags
& WINEDDBLT_COLORFILL
)
5408 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, fx
->u5
.dwFillColor
);
5409 flags
&= ~WINEDDBLT_COLORFILL
;
5412 if (flags
& WINEDDBLT_DEPTHFILL
)
5414 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
5416 if (flags
& WINEDDBLT_ROP
)
5418 /* Catch some degenerate cases here. */
5422 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, 0);
5424 case 0xaa0029: /* No-op */
5427 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, ~0U);
5429 case SRCCOPY
: /* Well, we do that below? */
5432 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx
->dwROP
, fx
->u5
.lpDDSPattern
);
5435 flags
&= ~WINEDDBLT_ROP
;
5437 if (flags
& WINEDDBLT_DDROPS
)
5439 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx
->dwDDROP
, fx
->u5
.lpDDSPattern
);
5441 /* Now the 'with source' blits. */
5444 int sx
, xinc
, sy
, yinc
;
5446 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
5449 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
5450 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
5452 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
5453 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
5456 xinc
= (srcwidth
<< 16) / dstwidth
;
5457 yinc
= (srcheight
<< 16) / dstheight
;
5461 /* No effects, we can cheat here. */
5462 if (dstwidth
== srcwidth
)
5464 if (dstheight
== srcheight
)
5466 /* No stretching in either direction. This needs to be as
5467 * fast as possible. */
5470 /* Check for overlapping surfaces. */
5471 if (src_surface
!= dst_surface
|| dst_rect
->top
< src_rect
->top
5472 || dst_rect
->right
<= src_rect
->left
|| src_rect
->right
<= dst_rect
->left
)
5474 /* No overlap, or dst above src, so copy from top downwards. */
5475 for (y
= 0; y
< dstheight
; ++y
)
5477 memcpy(dbuf
, sbuf
, width
);
5478 sbuf
+= src_map
.row_pitch
;
5479 dbuf
+= dst_map
.row_pitch
;
5482 else if (dst_rect
->top
> src_rect
->top
)
5484 /* Copy from bottom upwards. */
5485 sbuf
+= src_map
.row_pitch
* dstheight
;
5486 dbuf
+= dst_map
.row_pitch
* dstheight
;
5487 for (y
= 0; y
< dstheight
; ++y
)
5489 sbuf
-= src_map
.row_pitch
;
5490 dbuf
-= dst_map
.row_pitch
;
5491 memcpy(dbuf
, sbuf
, width
);
5496 /* Src and dst overlapping on the same line, use memmove. */
5497 for (y
= 0; y
< dstheight
; ++y
)
5499 memmove(dbuf
, sbuf
, width
);
5500 sbuf
+= src_map
.row_pitch
;
5501 dbuf
+= dst_map
.row_pitch
;
5507 /* Stretching in y direction only. */
5508 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5510 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5511 memcpy(dbuf
, sbuf
, width
);
5512 dbuf
+= dst_map
.row_pitch
;
5518 /* Stretching in X direction. */
5520 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5522 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5524 if ((sy
>> 16) == (last_sy
>> 16))
5526 /* This source row is the same as last source row -
5527 * Copy the already stretched row. */
5528 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, width
);
5532 #define STRETCH_ROW(type) \
5534 const type *s = (const type *)sbuf; \
5535 type *d = (type *)dbuf; \
5536 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5537 d[x] = s[sx >> 16]; \
5555 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
5559 s
= sbuf
+ 3 * (sx
>> 16);
5560 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5561 d
[0] = (pixel
) & 0xff;
5562 d
[1] = (pixel
>> 8) & 0xff;
5563 d
[2] = (pixel
>> 16) & 0xff;
5569 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
5570 hr
= WINED3DERR_NOTAVAILABLE
;
5575 dbuf
+= dst_map
.row_pitch
;
5582 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
5583 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
5584 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
5585 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
5587 /* The color keying flags are checked for correctness in ddraw */
5588 if (flags
& WINEDDBLT_KEYSRC
)
5590 keylow
= src_surface
->container
->src_blt_color_key
.color_space_low_value
;
5591 keyhigh
= src_surface
->container
->src_blt_color_key
.color_space_high_value
;
5593 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
5595 keylow
= fx
->ddckSrcColorkey
.color_space_low_value
;
5596 keyhigh
= fx
->ddckSrcColorkey
.color_space_high_value
;
5599 if (flags
& WINEDDBLT_KEYDEST
)
5601 /* Destination color keys are taken from the source surface! */
5602 destkeylow
= src_surface
->container
->dst_blt_color_key
.color_space_low_value
;
5603 destkeyhigh
= src_surface
->container
->dst_blt_color_key
.color_space_high_value
;
5605 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
5607 destkeylow
= fx
->ddckDestColorkey
.color_space_low_value
;
5608 destkeyhigh
= fx
->ddckDestColorkey
.color_space_high_value
;
5618 get_color_masks(src_format
, masks
);
5623 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
5626 if (flags
& WINEDDBLT_DDFX
)
5628 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
5631 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
5632 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dst_map
.row_pitch
);
5633 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
5635 if (fx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
5637 /* I don't think we need to do anything about this flag */
5638 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
5640 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
5643 dTopRight
= dTopLeft
;
5646 dBottomRight
= dBottomLeft
;
5648 dstxinc
= dstxinc
* -1;
5650 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
5653 dTopLeft
= dBottomLeft
;
5656 dTopRight
= dBottomRight
;
5658 dstyinc
= dstyinc
* -1;
5660 if (fx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
5662 /* I don't think we need to do anything about this flag */
5663 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
5665 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
5668 dBottomRight
= dTopLeft
;
5671 dBottomLeft
= dTopRight
;
5673 dstxinc
= dstxinc
* -1;
5674 dstyinc
= dstyinc
* -1;
5676 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
5679 dTopLeft
= dBottomLeft
;
5680 dBottomLeft
= dBottomRight
;
5681 dBottomRight
= dTopRight
;
5686 dstxinc
= dstxinc
* -1;
5688 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
5691 dTopLeft
= dTopRight
;
5692 dTopRight
= dBottomRight
;
5693 dBottomRight
= dBottomLeft
;
5698 dstyinc
= dstyinc
* -1;
5700 if (fx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
5702 /* I don't think we need to do anything about this flag */
5703 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
5706 flags
&= ~(WINEDDBLT_DDFX
);
5709 #define COPY_COLORKEY_FX(type) \
5712 type *d = (type *)dbuf, *dx, tmp; \
5713 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
5715 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
5717 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5719 tmp = s[sx >> 16]; \
5720 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
5721 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
5725 dx = (type *)(((BYTE *)dx) + dstxinc); \
5727 d = (type *)(((BYTE *)d) + dstyinc); \
5734 COPY_COLORKEY_FX(BYTE
);
5737 COPY_COLORKEY_FX(WORD
);
5740 COPY_COLORKEY_FX(DWORD
);
5745 BYTE
*d
= dbuf
, *dx
;
5746 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5748 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5750 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
5752 DWORD pixel
, dpixel
= 0;
5753 s
= sbuf
+ 3 * (sx
>>16);
5754 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5755 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
5756 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
5757 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
5759 dx
[0] = (pixel
) & 0xff;
5760 dx
[1] = (pixel
>> 8) & 0xff;
5761 dx
[2] = (pixel
>> 16) & 0xff;
5770 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
5771 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
* 8);
5772 hr
= WINED3DERR_NOTAVAILABLE
;
5774 #undef COPY_COLORKEY_FX
5780 if (flags
&& FIXME_ON(d3d_surface
))
5782 FIXME("\tUnsupported flags: %#x.\n", flags
);
5786 wined3d_surface_unmap(dst_surface
);
5787 if (src_surface
&& src_surface
!= dst_surface
)
5788 wined3d_surface_unmap(src_surface
);
5789 /* Release the converted surface, if any. */
5791 wined3d_texture_decref(src_texture
);
5796 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
5797 const RECT
*dst_rect
, const struct wined3d_color
*color
)
5799 static const RECT src_rect
;
5802 memset(&BltFx
, 0, sizeof(BltFx
));
5803 BltFx
.dwSize
= sizeof(BltFx
);
5804 BltFx
.u5
.dwFillColor
= wined3d_format_convert_from_float(dst_surface
, color
);
5805 return surface_cpu_blt(dst_surface
, dst_rect
, NULL
, &src_rect
,
5806 WINEDDBLT_COLORFILL
, &BltFx
, WINED3D_TEXF_POINT
);
5809 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
5810 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
5812 FIXME("Depth filling not implemented by cpu_blit.\n");
5813 return WINED3DERR_INVALIDCALL
;
5816 const struct blit_shader cpu_blit
= {
5822 cpu_blit_color_fill
,
5823 cpu_blit_depth_fill
,
5826 HRESULT CDECL
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
,
5827 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD flags
,
5828 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
5830 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
5831 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5832 DWORD src_ds_flags
, dst_ds_flags
;
5833 RECT src_rect
, dst_rect
;
5834 BOOL scale
, convert
;
5835 enum wined3d_conversion_type dst_convert_type
;
5836 struct wined3d_format dst_conv_fmt
;
5838 static const DWORD simple_blit
= WINEDDBLT_ASYNC
5839 | WINEDDBLT_COLORFILL
5841 | WINEDDBLT_DEPTHFILL
5842 | WINEDDBLT_DONOTWAIT
;
5844 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5845 dst_surface
, wine_dbgstr_rect(dst_rect_in
), src_surface
, wine_dbgstr_rect(src_rect_in
),
5846 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5847 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
5851 TRACE("dwSize %#x.\n", fx
->dwSize
);
5852 TRACE("dwDDFX %#x.\n", fx
->dwDDFX
);
5853 TRACE("dwROP %#x.\n", fx
->dwROP
);
5854 TRACE("dwDDROP %#x.\n", fx
->dwDDROP
);
5855 TRACE("dwRotationAngle %#x.\n", fx
->dwRotationAngle
);
5856 TRACE("dwZBufferOpCode %#x.\n", fx
->dwZBufferOpCode
);
5857 TRACE("dwZBufferLow %#x.\n", fx
->dwZBufferLow
);
5858 TRACE("dwZBufferHigh %#x.\n", fx
->dwZBufferHigh
);
5859 TRACE("dwZBufferBaseDest %#x.\n", fx
->dwZBufferBaseDest
);
5860 TRACE("dwZDestConstBitDepth %#x.\n", fx
->dwZDestConstBitDepth
);
5861 TRACE("lpDDSZBufferDest %p.\n", fx
->u1
.lpDDSZBufferDest
);
5862 TRACE("dwZSrcConstBitDepth %#x.\n", fx
->dwZSrcConstBitDepth
);
5863 TRACE("lpDDSZBufferSrc %p.\n", fx
->u2
.lpDDSZBufferSrc
);
5864 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx
->dwAlphaEdgeBlendBitDepth
);
5865 TRACE("dwAlphaEdgeBlend %#x.\n", fx
->dwAlphaEdgeBlend
);
5866 TRACE("dwReserved %#x.\n", fx
->dwReserved
);
5867 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx
->dwAlphaDestConstBitDepth
);
5868 TRACE("lpDDSAlphaDest %p.\n", fx
->u3
.lpDDSAlphaDest
);
5869 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx
->dwAlphaSrcConstBitDepth
);
5870 TRACE("lpDDSAlphaSrc %p.\n", fx
->u4
.lpDDSAlphaSrc
);
5871 TRACE("lpDDSPattern %p.\n", fx
->u5
.lpDDSPattern
);
5872 TRACE("ddckDestColorkey {%#x, %#x}.\n",
5873 fx
->ddckDestColorkey
.color_space_low_value
,
5874 fx
->ddckDestColorkey
.color_space_high_value
);
5875 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
5876 fx
->ddckSrcColorkey
.color_space_low_value
,
5877 fx
->ddckSrcColorkey
.color_space_high_value
);
5880 if (dst_surface
->resource
.map_count
|| (src_surface
&& src_surface
->resource
.map_count
))
5882 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
5883 return WINEDDERR_SURFACEBUSY
;
5886 surface_get_rect(dst_surface
, dst_rect_in
, &dst_rect
);
5888 if (dst_rect
.left
>= dst_rect
.right
|| dst_rect
.top
>= dst_rect
.bottom
5889 || dst_rect
.left
> dst_surface
->resource
.width
|| dst_rect
.left
< 0
5890 || dst_rect
.top
> dst_surface
->resource
.height
|| dst_rect
.top
< 0
5891 || dst_rect
.right
> dst_surface
->resource
.width
|| dst_rect
.right
< 0
5892 || dst_rect
.bottom
> dst_surface
->resource
.height
|| dst_rect
.bottom
< 0)
5894 WARN("The application gave us a bad destination rectangle.\n");
5895 return WINEDDERR_INVALIDRECT
;
5900 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
5902 if (src_rect
.left
>= src_rect
.right
|| src_rect
.top
>= src_rect
.bottom
5903 || src_rect
.left
> src_surface
->resource
.width
|| src_rect
.left
< 0
5904 || src_rect
.top
> src_surface
->resource
.height
|| src_rect
.top
< 0
5905 || src_rect
.right
> src_surface
->resource
.width
|| src_rect
.right
< 0
5906 || src_rect
.bottom
> src_surface
->resource
.height
|| src_rect
.bottom
< 0)
5908 WARN("Application gave us bad source rectangle for Blt.\n");
5909 return WINEDDERR_INVALIDRECT
;
5914 memset(&src_rect
, 0, sizeof(src_rect
));
5917 if (!fx
|| !(fx
->dwDDFX
))
5918 flags
&= ~WINEDDBLT_DDFX
;
5920 if (flags
& WINEDDBLT_WAIT
)
5921 flags
&= ~WINEDDBLT_WAIT
;
5923 if (flags
& WINEDDBLT_ASYNC
)
5925 static unsigned int once
;
5928 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
5929 flags
&= ~WINEDDBLT_ASYNC
;
5932 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
5933 if (flags
& WINEDDBLT_DONOTWAIT
)
5935 static unsigned int once
;
5938 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
5939 flags
&= ~WINEDDBLT_DONOTWAIT
;
5942 if (!device
->d3d_initialized
)
5944 WARN("D3D not initialized, using fallback.\n");
5948 /* We want to avoid invalidating the sysmem location for converted
5949 * surfaces, since otherwise we'd have to convert the data back when
5951 d3dfmt_get_conv(dst_surface
, TRUE
, TRUE
, &dst_conv_fmt
, &dst_convert_type
);
5952 if (dst_convert_type
!= WINED3D_CT_NONE
|| dst_conv_fmt
.convert
|| dst_surface
->flags
& SFLAG_CONVERTED
)
5954 WARN_(d3d_perf
)("Converted surface, using CPU blit.\n");
5958 if (flags
& ~simple_blit
)
5960 WARN_(d3d_perf
)("Using fallback for complex blit (%#x).\n", flags
);
5965 src_swapchain
= src_surface
->swapchain
;
5967 src_swapchain
= NULL
;
5969 dst_swapchain
= dst_surface
->swapchain
;
5971 /* This isn't strictly needed. FBO blits for example could deal with
5972 * cross-swapchain blits by first downloading the source to a texture
5973 * before switching to the destination context. We just have this here to
5974 * not have to deal with the issue, since cross-swapchain blits should be
5976 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
5978 FIXME("Using fallback for cross-swapchain blit.\n");
5983 && (src_rect
.right
- src_rect
.left
!= dst_rect
.right
- dst_rect
.left
5984 || src_rect
.bottom
- src_rect
.top
!= dst_rect
.bottom
- dst_rect
.top
);
5985 convert
= src_surface
&& src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
;
5987 dst_ds_flags
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5989 src_ds_flags
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5993 if (src_ds_flags
|| dst_ds_flags
)
5995 if (flags
& WINEDDBLT_DEPTHFILL
)
5999 TRACE("Depth fill.\n");
6001 if (!surface_convert_depth_to_float(dst_surface
, fx
->u5
.dwFillDepth
, &depth
))
6002 return WINED3DERR_INVALIDCALL
;
6004 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, &dst_rect
, depth
)))
6009 if (src_ds_flags
!= dst_ds_flags
)
6011 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
6012 return WINED3DERR_INVALIDCALL
;
6015 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_surface
->draw_binding
, &src_rect
,
6016 dst_surface
, dst_surface
->draw_binding
, &dst_rect
)))
6022 /* In principle this would apply to depth blits as well, but we don't
6023 * implement those in the CPU blitter at the moment. */
6024 if ((dst_surface
->locations
& dst_surface
->map_binding
)
6025 && (!src_surface
|| (src_surface
->locations
& src_surface
->map_binding
)))
6028 TRACE("Not doing sysmem blit because of scaling.\n");
6030 TRACE("Not doing sysmem blit because of format conversion.\n");
6035 if (flags
& WINEDDBLT_COLORFILL
)
6037 struct wined3d_color color
;
6039 TRACE("Color fill.\n");
6041 if (!surface_convert_color_to_float(dst_surface
, fx
->u5
.dwFillColor
, &color
))
6044 if (SUCCEEDED(surface_color_fill(dst_surface
, &dst_rect
, &color
)))
6049 TRACE("Color blit.\n");
6052 if ((src_surface
->locations
& WINED3D_LOCATION_SYSMEM
)
6053 && !(dst_surface
->locations
& WINED3D_LOCATION_SYSMEM
))
6056 TRACE("Not doing upload because of scaling.\n");
6058 TRACE("Not doing upload because of format conversion.\n");
6061 POINT dst_point
= {dst_rect
.left
, dst_rect
.top
};
6063 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, &src_rect
)))
6065 if (!surface_is_offscreen(dst_surface
))
6066 surface_load_location(dst_surface
, dst_surface
->draw_binding
);
6072 /* Use present for back -> front blits. The idea behind this is
6073 * that present is potentially faster than a blit, in particular
6074 * when FBO blits aren't available. Some ddraw applications like
6075 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
6076 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
6077 * applications can't blit directly to the frontbuffer. */
6078 if (dst_swapchain
&& dst_swapchain
->back_buffers
6079 && dst_surface
== dst_swapchain
->front_buffer
6080 && src_surface
== dst_swapchain
->back_buffers
[0])
6082 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
6084 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
6086 /* Set the swap effect to COPY, we don't want the backbuffer
6087 * to become undefined. */
6088 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
6089 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, NULL
, 0);
6090 dst_swapchain
->desc
.swap_effect
= swap_effect
;
6095 if (fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
6096 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
6097 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
6099 TRACE("Using FBO blit.\n");
6101 surface_blt_fbo(device
, filter
,
6102 src_surface
, src_surface
->draw_binding
, &src_rect
,
6103 dst_surface
, dst_surface
->draw_binding
, &dst_rect
);
6104 surface_validate_location(dst_surface
, dst_surface
->draw_binding
);
6105 surface_invalidate_location(dst_surface
, ~dst_surface
->draw_binding
);
6110 if (arbfp_blit
.blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
6111 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
6112 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
6114 TRACE("Using arbfp blit.\n");
6116 if (SUCCEEDED(arbfp_blit_surface(device
, filter
, src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
6123 /* Special cases for render targets. */
6124 if (SUCCEEDED(surface_blt_special(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
)))
6129 /* For the rest call the X11 surface implementation. For render targets
6130 * this should be implemented OpenGL accelerated in surface_blt_special(),
6131 * other blits are rather rare. */
6132 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
6135 static HRESULT
surface_init(struct wined3d_surface
*surface
, struct wined3d_texture
*container
,
6136 const struct wined3d_resource_desc
*desc
, GLenum target
, GLint level
, DWORD flags
)
6138 struct wined3d_device
*device
= container
->resource
.device
;
6139 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6140 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, desc
->format
);
6141 UINT multisample_quality
= desc
->multisample_quality
;
6142 BOOL lockable
= flags
& WINED3D_SURFACE_MAPPABLE
;
6143 unsigned int resource_size
;
6146 if (multisample_quality
> 0)
6148 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality
);
6149 multisample_quality
= 0;
6152 /* Quick lockable sanity check.
6153 * TODO: remove this after surfaces, usage and lockability have been debugged properly
6154 * this function is too deep to need to care about things like this.
6155 * Levels need to be checked too, since they all affect what can be done. */
6158 case WINED3D_POOL_MANAGED
:
6159 if (desc
->usage
& WINED3DUSAGE_DYNAMIC
)
6160 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
6163 case WINED3D_POOL_DEFAULT
:
6164 if (lockable
&& !(desc
->usage
& (WINED3DUSAGE_DYNAMIC
6165 | WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
6166 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
6169 case WINED3D_POOL_SCRATCH
:
6170 case WINED3D_POOL_SYSTEM_MEM
:
6174 FIXME("Unknown pool %#x.\n", desc
->pool
);
6178 if (desc
->usage
& WINED3DUSAGE_RENDERTARGET
&& desc
->pool
!= WINED3D_POOL_DEFAULT
)
6179 FIXME("Trying to create a render target that isn't in the default pool.\n");
6181 /* FIXME: Check that the format is supported by the device. */
6183 resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, desc
->width
, desc
->height
, 1);
6185 return WINED3DERR_INVALIDCALL
;
6187 if (device
->wined3d
->flags
& WINED3D_NO3D
)
6188 surface
->surface_ops
= &gdi_surface_ops
;
6190 surface
->surface_ops
= &surface_ops
;
6192 if (FAILED(hr
= resource_init(&surface
->resource
, device
, WINED3D_RTYPE_SURFACE
, format
,
6193 desc
->multisample_type
, multisample_quality
, desc
->usage
, desc
->pool
, desc
->width
, desc
->height
, 1,
6194 resource_size
, NULL
, &wined3d_null_parent_ops
, &surface_resource_ops
)))
6196 WARN("Failed to initialize resource, returning %#x.\n", hr
);
6200 surface_set_container(surface
, container
);
6201 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
6202 list_init(&surface
->renderbuffers
);
6203 list_init(&surface
->overlays
);
6206 if (target
!= GL_TEXTURE_RECTANGLE_ARB
)
6207 surface
->flags
|= SFLAG_NORMCOORD
;
6208 if (flags
& WINED3D_SURFACE_DISCARD
)
6209 surface
->flags
|= SFLAG_DISCARD
;
6210 if (flags
& WINED3D_SURFACE_PIN_SYSMEM
)
6211 surface
->flags
|= SFLAG_PIN_SYSMEM
;
6212 if (lockable
|| desc
->format
== WINED3DFMT_D16_LOCKABLE
)
6213 surface
->resource
.access_flags
|= WINED3D_RESOURCE_ACCESS_CPU
;
6215 surface
->map_binding
= WINED3D_LOCATION_SYSMEM
;
6216 surface
->texture_target
= target
;
6217 surface
->texture_level
= level
;
6219 /* Call the private setup routine */
6220 hr
= surface
->surface_ops
->surface_private_setup(surface
);
6223 ERR("Private setup failed, returning %#x\n", hr
);
6224 surface_set_container(surface
, NULL
);
6225 surface_cleanup(surface
);
6229 /* Similar to lockable rendertargets above, creating the DIB section
6230 * during surface initialization prevents the sysmem pointer from changing
6231 * after a wined3d_surface_getdc() call. */
6232 if ((desc
->usage
& WINED3DUSAGE_OWNDC
) && !surface
->hDC
6233 && SUCCEEDED(surface_create_dib_section(surface
)))
6234 surface
->map_binding
= WINED3D_LOCATION_DIB
;
6236 if (surface
->map_binding
== WINED3D_LOCATION_DIB
)
6238 wined3d_resource_free_sysmem(&surface
->resource
);
6239 surface_validate_location(surface
, WINED3D_LOCATION_DIB
);
6240 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
6246 HRESULT
wined3d_surface_create(struct wined3d_texture
*container
, const struct wined3d_resource_desc
*desc
,
6247 GLenum target
, GLint level
, DWORD flags
, struct wined3d_surface
**surface
)
6249 struct wined3d_device_parent
*device_parent
= container
->resource
.device
->device_parent
;
6250 const struct wined3d_parent_ops
*parent_ops
;
6251 struct wined3d_surface
*object
;
6255 TRACE("container %p, width %u, height %u, format %s, usage %s (%#x), pool %s, "
6256 "multisample_type %#x, multisample_quality %u, target %#x, level %d, flags %#x, surface %p.\n",
6257 container
, desc
->width
, desc
->height
, debug_d3dformat(desc
->format
),
6258 debug_d3dusage(desc
->usage
), desc
->usage
, debug_d3dpool(desc
->pool
),
6259 desc
->multisample_type
, desc
->multisample_quality
, target
, level
, flags
, surface
);
6261 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
6262 return E_OUTOFMEMORY
;
6264 if (FAILED(hr
= surface_init(object
, container
, desc
, target
, level
, flags
)))
6266 WARN("Failed to initialize surface, returning %#x.\n", hr
);
6267 HeapFree(GetProcessHeap(), 0, object
);
6271 if (FAILED(hr
= device_parent
->ops
->surface_created(device_parent
,
6272 wined3d_texture_get_parent(container
), object
, &parent
, &parent_ops
)))
6274 WARN("Failed to create surface parent, hr %#x.\n", hr
);
6275 surface_set_container(object
, NULL
);
6276 wined3d_surface_decref(object
);
6280 TRACE("Created surface %p, parent %p, parent_ops %p.\n", object
, parent
, parent_ops
);
6282 object
->resource
.parent
= parent
;
6283 object
->resource
.parent_ops
= parent_ops
;