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-2008 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
);
36 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
37 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
38 const WINEDDBLTFX
*fx
, WINED3DTEXTUREFILTERTYPE filter
);
39 static HRESULT
IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
40 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*fx
,
41 WINED3DTEXTUREFILTERTYPE filter
);
43 static void surface_cleanup(struct wined3d_surface
*surface
)
45 TRACE("surface %p.\n", surface
);
47 if (surface
->texture_name
|| (surface
->flags
& SFLAG_PBO
)
48 || surface
->rb_multisample
|| surface
->rb_resolved
49 || !list_empty(&surface
->renderbuffers
))
51 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
52 const struct wined3d_gl_info
*gl_info
;
53 struct wined3d_context
*context
;
55 context
= context_acquire(surface
->resource
.device
, NULL
);
56 gl_info
= context
->gl_info
;
60 if (surface
->texture_name
)
62 TRACE("Deleting texture %u.\n", surface
->texture_name
);
63 glDeleteTextures(1, &surface
->texture_name
);
66 if (surface
->flags
& SFLAG_PBO
)
68 TRACE("Deleting PBO %u.\n", surface
->pbo
);
69 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
72 if (surface
->rb_multisample
)
74 TRACE("Deleting multisample renderbuffer %u.\n", surface
->rb_multisample
);
75 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
78 if (surface
->rb_resolved
)
80 TRACE("Deleting resolved renderbuffer %u.\n", surface
->rb_resolved
);
81 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
84 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
86 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
87 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
88 HeapFree(GetProcessHeap(), 0, entry
);
93 context_release(context
);
96 if (surface
->flags
& SFLAG_DIBSECTION
)
99 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
100 DeleteDC(surface
->hDC
);
101 /* Release the DIB section. */
102 DeleteObject(surface
->dib
.DIBsection
);
103 surface
->dib
.bitmap_data
= NULL
;
104 surface
->resource
.allocatedMemory
= NULL
;
107 if (surface
->flags
& SFLAG_USERPTR
)
108 wined3d_surface_set_mem(surface
, NULL
);
109 if (surface
->overlay_dest
)
110 list_remove(&surface
->overlay_entry
);
112 HeapFree(GetProcessHeap(), 0, surface
->palette9
);
114 resource_cleanup(&surface
->resource
);
117 void surface_update_draw_binding(struct wined3d_surface
*surface
)
119 if (!surface_is_offscreen(surface
) || wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
)
120 surface
->draw_binding
= SFLAG_INDRAWABLE
;
121 else if (surface
->resource
.multisample_type
)
122 surface
->draw_binding
= SFLAG_INRB_MULTISAMPLE
;
124 surface
->draw_binding
= SFLAG_INTEXTURE
;
127 void surface_set_container(struct wined3d_surface
*surface
, enum wined3d_container_type type
, void *container
)
129 TRACE("surface %p, container %p.\n", surface
, container
);
131 if (!container
&& type
!= WINED3D_CONTAINER_NONE
)
132 ERR("Setting NULL container of type %#x.\n", type
);
134 if (type
== WINED3D_CONTAINER_SWAPCHAIN
)
136 surface
->get_drawable_size
= get_drawable_size_swapchain
;
140 switch (wined3d_settings
.offscreen_rendering_mode
)
143 surface
->get_drawable_size
= get_drawable_size_fbo
;
147 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
151 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
156 surface
->container
.type
= type
;
157 surface
->container
.u
.base
= container
;
158 surface_update_draw_binding(surface
);
165 enum tex_types tex_type
;
166 GLfloat coords
[4][3];
177 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
179 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
180 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
181 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
182 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
185 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
187 GLfloat (*coords
)[3] = info
->coords
;
193 FIXME("Unsupported texture target %#x\n", target
);
194 /* Fall back to GL_TEXTURE_2D */
196 info
->binding
= GL_TEXTURE_BINDING_2D
;
197 info
->bind_target
= GL_TEXTURE_2D
;
198 info
->tex_type
= tex_2d
;
199 coords
[0][0] = (float)rect
->left
/ w
;
200 coords
[0][1] = (float)rect
->top
/ h
;
203 coords
[1][0] = (float)rect
->right
/ w
;
204 coords
[1][1] = (float)rect
->top
/ h
;
207 coords
[2][0] = (float)rect
->left
/ w
;
208 coords
[2][1] = (float)rect
->bottom
/ h
;
211 coords
[3][0] = (float)rect
->right
/ w
;
212 coords
[3][1] = (float)rect
->bottom
/ h
;
216 case GL_TEXTURE_RECTANGLE_ARB
:
217 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
218 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
219 info
->tex_type
= tex_rect
;
220 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
221 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
222 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
223 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
226 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
227 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
228 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
229 info
->tex_type
= tex_cube
;
230 cube_coords_float(rect
, w
, h
, &f
);
232 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
233 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
234 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
235 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
238 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
239 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
240 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
241 info
->tex_type
= tex_cube
;
242 cube_coords_float(rect
, w
, h
, &f
);
244 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
245 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
246 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
247 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
250 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
251 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
252 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
253 info
->tex_type
= tex_cube
;
254 cube_coords_float(rect
, w
, h
, &f
);
256 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
257 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
258 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
259 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
262 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
263 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
264 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
265 info
->tex_type
= tex_cube
;
266 cube_coords_float(rect
, w
, h
, &f
);
268 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
269 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
270 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
271 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
274 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
275 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
276 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
277 info
->tex_type
= tex_cube
;
278 cube_coords_float(rect
, w
, h
, &f
);
280 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
281 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
282 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
283 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
286 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
287 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
288 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
289 info
->tex_type
= tex_cube
;
290 cube_coords_float(rect
, w
, h
, &f
);
292 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
293 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
294 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
295 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
300 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
303 *rect_out
= *rect_in
;
308 rect_out
->right
= surface
->resource
.width
;
309 rect_out
->bottom
= surface
->resource
.height
;
313 /* GL locking and context activation is done by the caller */
314 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
315 const RECT
*src_rect
, const RECT
*dst_rect
, WINED3DTEXTUREFILTERTYPE Filter
)
317 struct blt_info info
;
319 surface_get_blt_info(src_surface
->texture_target
, src_rect
, src_surface
->pow2Width
, src_surface
->pow2Height
, &info
);
321 glEnable(info
.bind_target
);
322 checkGLcall("glEnable(bind_target)");
324 context_bind_texture(context
, info
.bind_target
, src_surface
->texture_name
);
326 /* Filtering for StretchRect */
327 glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
,
328 wined3d_gl_mag_filter(magLookup
, Filter
));
329 checkGLcall("glTexParameteri");
330 glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
331 wined3d_gl_min_mip_filter(minMipLookup
, Filter
, WINED3DTEXF_NONE
));
332 checkGLcall("glTexParameteri");
333 glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
334 glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
335 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
336 glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
337 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
338 checkGLcall("glTexEnvi");
341 glBegin(GL_TRIANGLE_STRIP
);
342 glTexCoord3fv(info
.coords
[0]);
343 glVertex2i(dst_rect
->left
, dst_rect
->top
);
345 glTexCoord3fv(info
.coords
[1]);
346 glVertex2i(dst_rect
->right
, dst_rect
->top
);
348 glTexCoord3fv(info
.coords
[2]);
349 glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
351 glTexCoord3fv(info
.coords
[3]);
352 glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
355 /* Unbind the texture */
356 context_bind_texture(context
, info
.bind_target
, 0);
358 /* We changed the filtering settings on the texture. Inform the
359 * container about this to get the filters reset properly next draw. */
360 if (src_surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
362 struct wined3d_texture
*texture
= src_surface
->container
.u
.texture
;
363 texture
->texture_rgb
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
364 texture
->texture_rgb
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
365 texture
->texture_rgb
.states
[WINED3DTEXSTA_MIPFILTER
] = WINED3DTEXF_NONE
;
366 texture
->texture_rgb
.states
[WINED3DTEXSTA_SRGBTEXTURE
] = FALSE
;
370 static HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
372 const struct wined3d_format
*format
= surface
->resource
.format
;
380 TRACE("surface %p.\n", surface
);
382 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
384 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
385 return WINED3DERR_INVALIDCALL
;
388 switch (format
->byte_count
)
392 /* Allocate extra space to store the RGB bit masks. */
393 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
397 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
401 /* Allocate extra space for a palette. */
402 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
403 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
408 return E_OUTOFMEMORY
;
410 /* Some applications access the surface in via DWORDs, and do not take
411 * the necessary care at the end of the surface. So we need at least
412 * 4 extra bytes at the end of the surface. Check against the page size,
413 * if the last page used for the surface has at least 4 spare bytes we're
414 * safe, otherwise add an extra line to the DIB section. */
415 GetSystemInfo(&sysInfo
);
416 if( ((surface
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4)
419 TRACE("Adding an extra line to the DIB section.\n");
422 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
423 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
424 b_info
->bmiHeader
.biWidth
= wined3d_surface_get_pitch(surface
) / format
->byte_count
;
425 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
- extraline
;
426 b_info
->bmiHeader
.biSizeImage
= (surface
->resource
.height
+ extraline
)
427 * wined3d_surface_get_pitch(surface
);
428 b_info
->bmiHeader
.biPlanes
= 1;
429 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
431 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
432 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
433 b_info
->bmiHeader
.biClrUsed
= 0;
434 b_info
->bmiHeader
.biClrImportant
= 0;
436 /* Get the bit masks */
437 masks
= (DWORD
*)b_info
->bmiColors
;
438 switch (surface
->resource
.format
->id
)
440 case WINED3DFMT_B8G8R8_UNORM
:
441 usage
= DIB_RGB_COLORS
;
442 b_info
->bmiHeader
.biCompression
= BI_RGB
;
445 case WINED3DFMT_B5G5R5X1_UNORM
:
446 case WINED3DFMT_B5G5R5A1_UNORM
:
447 case WINED3DFMT_B4G4R4A4_UNORM
:
448 case WINED3DFMT_B4G4R4X4_UNORM
:
449 case WINED3DFMT_B2G3R3_UNORM
:
450 case WINED3DFMT_B2G3R3A8_UNORM
:
451 case WINED3DFMT_R10G10B10A2_UNORM
:
452 case WINED3DFMT_R8G8B8A8_UNORM
:
453 case WINED3DFMT_R8G8B8X8_UNORM
:
454 case WINED3DFMT_B10G10R10A2_UNORM
:
455 case WINED3DFMT_B5G6R5_UNORM
:
456 case WINED3DFMT_R16G16B16A16_UNORM
:
458 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
459 masks
[0] = format
->red_mask
;
460 masks
[1] = format
->green_mask
;
461 masks
[2] = format
->blue_mask
;
465 /* Don't know palette */
466 b_info
->bmiHeader
.biCompression
= BI_RGB
;
471 if (!(dc
= GetDC(0)))
473 HeapFree(GetProcessHeap(), 0, b_info
);
474 return HRESULT_FROM_WIN32(GetLastError());
477 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
478 b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
,
479 b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
480 surface
->dib
.DIBsection
= CreateDIBSection(dc
, b_info
, usage
, &surface
->dib
.bitmap_data
, 0, 0);
483 if (!surface
->dib
.DIBsection
)
485 ERR("Failed to create DIB section.\n");
486 HeapFree(GetProcessHeap(), 0, b_info
);
487 return HRESULT_FROM_WIN32(GetLastError());
490 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
491 /* Copy the existing surface to the dib section. */
492 if (surface
->resource
.allocatedMemory
)
494 memcpy(surface
->dib
.bitmap_data
, surface
->resource
.allocatedMemory
,
495 surface
->resource
.height
* wined3d_surface_get_pitch(surface
));
499 /* This is to make maps read the GL texture although memory is allocated. */
500 surface
->flags
&= ~SFLAG_INSYSMEM
;
502 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
504 HeapFree(GetProcessHeap(), 0, b_info
);
506 /* Now allocate a DC. */
507 surface
->hDC
= CreateCompatibleDC(0);
508 surface
->dib
.holdbitmap
= SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
509 TRACE("Using wined3d palette %p.\n", surface
->palette
);
510 SelectPalette(surface
->hDC
, surface
->palette
? surface
->palette
->hpal
: 0, FALSE
);
512 surface
->flags
|= SFLAG_DIBSECTION
;
514 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
515 surface
->resource
.heapMemory
= NULL
;
520 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
522 struct wined3d_device
*device
= surface
->resource
.device
;
523 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
525 TRACE("surface %p.\n", surface
);
527 /* Performance optimization: Count how often a surface is locked, if it is
528 * locked regularly do not throw away the system memory copy. This avoids
529 * the need to download the surface from OpenGL all the time. The surface
530 * is still downloaded if the OpenGL texture is changed. */
531 if (!(surface
->flags
& SFLAG_DYNLOCK
))
533 if (++surface
->lockCount
> MAXLOCKCOUNT
)
535 TRACE("Surface is locked regularly, not freeing the system memory copy any more.\n");
536 surface
->flags
|= SFLAG_DYNLOCK
;
540 /* Create a PBO for dynamically locked surfaces but don't do it for
541 * converted or NPOT surfaces. Also don't create a PBO for systemmem
543 if (gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
] && (surface
->flags
& SFLAG_DYNLOCK
)
544 && !(surface
->flags
& (SFLAG_PBO
| SFLAG_CONVERTED
| SFLAG_NONPOW2
))
545 && (surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
))
547 struct wined3d_context
*context
;
550 context
= context_acquire(device
, NULL
);
553 GL_EXTCALL(glGenBuffersARB(1, &surface
->pbo
));
554 error
= 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 surface
->resource
.allocatedMemory
, GL_STREAM_DRAW_ARB
));
565 checkGLcall("glBufferDataARB");
567 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
568 checkGLcall("glBindBufferARB");
570 /* We don't need the system memory anymore and we can't even use it for PBOs. */
571 if (!(surface
->flags
& SFLAG_CLIENT
))
573 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
574 surface
->resource
.heapMemory
= NULL
;
576 surface
->resource
.allocatedMemory
= NULL
;
577 surface
->flags
|= SFLAG_PBO
;
579 context_release(context
);
581 else if (!(surface
->resource
.allocatedMemory
|| surface
->flags
& SFLAG_PBO
))
583 /* Whatever surface we have, make sure that there is memory allocated
584 * for the downloaded copy, or a PBO to map. */
585 if (!surface
->resource
.heapMemory
)
586 surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
+ RESOURCE_ALIGNMENT
);
588 surface
->resource
.allocatedMemory
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
589 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
591 if (surface
->flags
& SFLAG_INSYSMEM
)
592 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
596 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
598 if (surface
->flags
& SFLAG_DONOTFREE
)
601 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
602 surface
->resource
.allocatedMemory
= NULL
;
603 surface
->resource
.heapMemory
= NULL
;
604 surface_modify_location(surface
, SFLAG_INSYSMEM
, FALSE
);
607 /* Context activation is done by the caller. */
608 static void surface_bind_and_dirtify(struct wined3d_surface
*surface
,
609 struct wined3d_context
*context
, BOOL srgb
)
611 struct wined3d_device
*device
= surface
->resource
.device
;
612 DWORD active_sampler
;
614 /* We don't need a specific texture unit, but after binding the texture
615 * the current unit is dirty. Read the unit back instead of switching to
616 * 0, this avoids messing around with the state manager's GL states. The
617 * current texture unit should always be a valid one.
619 * To be more specific, this is tricky because we can implicitly be
620 * called from sampler() in state.c. This means we can't touch anything
621 * other than whatever happens to be the currently active texture, or we
622 * would risk marking already applied sampler states dirty again. */
623 active_sampler
= device
->rev_tex_unit_map
[context
->active_texture
];
625 if (active_sampler
!= WINED3D_UNMAPPED_STAGE
)
626 device_invalidate_state(device
, STATE_SAMPLER(active_sampler
));
627 surface_bind(surface
, context
, srgb
);
630 static void surface_force_reload(struct wined3d_surface
*surface
)
632 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
635 static void surface_release_client_storage(struct wined3d_surface
*surface
)
637 struct wined3d_context
*context
= context_acquire(surface
->resource
.device
, NULL
);
640 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
641 if (surface
->texture_name
)
643 surface_bind_and_dirtify(surface
, context
, FALSE
);
644 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
645 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
647 if (surface
->texture_name_srgb
)
649 surface_bind_and_dirtify(surface
, context
, TRUE
);
650 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
651 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
653 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
656 context_release(context
);
658 surface_modify_location(surface
, SFLAG_INSRGBTEX
, FALSE
);
659 surface_modify_location(surface
, SFLAG_INTEXTURE
, FALSE
);
660 surface_force_reload(surface
);
663 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
665 /* TODO: Check against the maximum texture sizes supported by the video card. */
666 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
667 unsigned int pow2Width
, pow2Height
;
669 TRACE("surface %p.\n", surface
);
671 surface
->texture_name
= 0;
672 surface
->texture_target
= GL_TEXTURE_2D
;
674 /* Non-power2 support */
675 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
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
)
697 FIXME("(%p) Compressed 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
== WINED3DPOOL_DEFAULT
|| surface
->resource
.pool
== WINED3DPOOL_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
);
734 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
735 * and EXT_PALETTED_TEXTURE is used in combination with texture
736 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
737 * EXT_PALETTED_TEXTURE doesn't work in combination with
738 * ARB_TEXTURE_RECTANGLE. */
739 if (surface
->flags
& SFLAG_NONPOW2
&& gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
740 && !(surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
741 && gl_info
->supported
[EXT_PALETTED_TEXTURE
]
742 && wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
))
744 surface
->texture_target
= GL_TEXTURE_RECTANGLE_ARB
;
745 surface
->pow2Width
= surface
->resource
.width
;
746 surface
->pow2Height
= surface
->resource
.height
;
747 surface
->flags
&= ~(SFLAG_NONPOW2
| SFLAG_NORMCOORD
);
751 switch (wined3d_settings
.offscreen_rendering_mode
)
754 surface
->get_drawable_size
= get_drawable_size_fbo
;
758 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
762 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
763 return WINED3DERR_INVALIDCALL
;
766 surface
->flags
|= SFLAG_INSYSMEM
;
771 static void surface_realize_palette(struct wined3d_surface
*surface
)
773 struct wined3d_palette
*palette
= surface
->palette
;
775 TRACE("surface %p.\n", surface
);
777 if (!palette
) return;
779 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
780 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
782 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
784 /* Make sure the texture is up to date. This call doesn't do
785 * anything if the texture is already up to date. */
786 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
788 /* We want to force a palette refresh, so mark the drawable as not being up to date */
789 if (!surface_is_offscreen(surface
))
790 surface_modify_location(surface
, SFLAG_INDRAWABLE
, FALSE
);
794 if (!(surface
->flags
& SFLAG_INSYSMEM
))
796 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
797 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
799 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
803 if (surface
->flags
& SFLAG_DIBSECTION
)
808 TRACE("Updating the DC's palette.\n");
810 for (i
= 0; i
< 256; ++i
)
812 col
[i
].rgbRed
= palette
->palents
[i
].peRed
;
813 col
[i
].rgbGreen
= palette
->palents
[i
].peGreen
;
814 col
[i
].rgbBlue
= palette
->palents
[i
].peBlue
;
815 col
[i
].rgbReserved
= 0;
817 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
820 /* Propagate the changes to the drawable when we have a palette. */
821 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
822 surface_load_location(surface
, surface
->draw_binding
, NULL
);
825 static HRESULT
surface_draw_overlay(struct wined3d_surface
*surface
)
829 /* If there's no destination surface there is nothing to do. */
830 if (!surface
->overlay_dest
)
833 /* Blt calls ModifyLocation on the dest surface, which in turn calls
834 * DrawOverlay to update the overlay. Prevent an endless recursion. */
835 if (surface
->overlay_dest
->flags
& SFLAG_INOVERLAYDRAW
)
838 surface
->overlay_dest
->flags
|= SFLAG_INOVERLAYDRAW
;
839 hr
= wined3d_surface_blt(surface
->overlay_dest
, &surface
->overlay_destrect
, surface
,
840 &surface
->overlay_srcrect
, WINEDDBLT_WAIT
, NULL
, WINED3DTEXF_LINEAR
);
841 surface
->overlay_dest
->flags
&= ~SFLAG_INOVERLAYDRAW
;
846 static void surface_preload(struct wined3d_surface
*surface
)
848 TRACE("surface %p.\n", surface
);
850 surface_internal_preload(surface
, SRGB_ANY
);
853 static void surface_map(struct wined3d_surface
*surface
, const RECT
*rect
, DWORD flags
)
855 struct wined3d_device
*device
= surface
->resource
.device
;
856 const RECT
*pass_rect
= rect
;
858 TRACE("surface %p, rect %s, flags %#x.\n",
859 surface
, wine_dbgstr_rect(rect
), flags
);
861 if (flags
& WINED3DLOCK_DISCARD
)
863 TRACE("WINED3DLOCK_DISCARD flag passed, marking SYSMEM as up to date.\n");
864 surface_prepare_system_memory(surface
);
865 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
869 /* surface_load_location() does not check if the rectangle specifies
870 * the full surface. Most callers don't need that, so do it here. */
871 if (rect
&& !rect
->top
&& !rect
->left
872 && rect
->right
== surface
->resource
.width
873 && rect
->bottom
== surface
->resource
.height
)
876 if (!(wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
877 && ((surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
878 || surface
== device
->fb
.render_targets
[0])))
879 surface_load_location(surface
, SFLAG_INSYSMEM
, pass_rect
);
882 if (surface
->flags
& SFLAG_PBO
)
884 const struct wined3d_gl_info
*gl_info
;
885 struct wined3d_context
*context
;
887 context
= context_acquire(device
, NULL
);
888 gl_info
= context
->gl_info
;
891 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
892 checkGLcall("glBindBufferARB");
894 /* This shouldn't happen but could occur if some other function
895 * didn't handle the PBO properly. */
896 if (surface
->resource
.allocatedMemory
)
897 ERR("The surface already has PBO memory allocated.\n");
899 surface
->resource
.allocatedMemory
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
900 checkGLcall("glMapBufferARB");
902 /* Make sure the PBO isn't set anymore in order not to break non-PBO
904 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
905 checkGLcall("glBindBufferARB");
908 context_release(context
);
911 if (!(flags
& (WINED3DLOCK_NO_DIRTY_UPDATE
| WINED3DLOCK_READONLY
)))
914 surface_add_dirty_rect(surface
, NULL
);
921 b
.Right
= rect
->right
;
922 b
.Bottom
= rect
->bottom
;
925 surface_add_dirty_rect(surface
, &b
);
930 static void surface_unmap(struct wined3d_surface
*surface
)
932 struct wined3d_device
*device
= surface
->resource
.device
;
935 TRACE("surface %p.\n", surface
);
937 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
939 if (surface
->flags
& SFLAG_PBO
)
941 const struct wined3d_gl_info
*gl_info
;
942 struct wined3d_context
*context
;
944 TRACE("Freeing PBO memory.\n");
946 context
= context_acquire(device
, NULL
);
947 gl_info
= context
->gl_info
;
950 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
951 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
952 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
953 checkGLcall("glUnmapBufferARB");
955 context_release(context
);
957 surface
->resource
.allocatedMemory
= NULL
;
960 TRACE("dirtyfied %u.\n", surface
->flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
) ? 0 : 1);
962 if (surface
->flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
))
964 TRACE("Not dirtified, nothing to do.\n");
968 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
969 || (device
->fb
.render_targets
&& surface
== device
->fb
.render_targets
[0]))
971 if (wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
)
973 static BOOL warned
= FALSE
;
976 ERR("The application tries to write to the render target, but render target locking is disabled.\n");
982 if (!surface
->dirtyRect
.left
&& !surface
->dirtyRect
.top
983 && surface
->dirtyRect
.right
== surface
->resource
.width
984 && surface
->dirtyRect
.bottom
== surface
->resource
.height
)
990 /* TODO: Proper partial rectangle tracking. */
992 surface
->flags
|= SFLAG_INSYSMEM
;
995 surface_load_location(surface
, surface
->draw_binding
, fullsurface
? NULL
: &surface
->dirtyRect
);
997 /* Partial rectangle tracking is not commonly implemented, it is only
998 * done for render targets. INSYSMEM was set before to tell
999 * surface_load_location() where to read the rectangle from.
1000 * Indrawable is set because all modifications from the partial
1001 * sysmem copy are written back to the drawable, thus the surface is
1002 * merged again in the drawable. The sysmem copy is not fully up to
1003 * date because only a subrectangle was read in Map(). */
1006 surface_modify_location(surface
, surface
->draw_binding
, TRUE
);
1007 surface_evict_sysmem(surface
);
1010 surface
->dirtyRect
.left
= surface
->resource
.width
;
1011 surface
->dirtyRect
.top
= surface
->resource
.height
;
1012 surface
->dirtyRect
.right
= 0;
1013 surface
->dirtyRect
.bottom
= 0;
1015 else if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
1017 FIXME("Depth / stencil buffer locking is not implemented.\n");
1021 /* Overlays have to be redrawn manually after changes with the GL implementation */
1022 if (surface
->overlay_dest
)
1023 surface
->surface_ops
->surface_draw_overlay(surface
);
1026 static HRESULT
surface_getdc(struct wined3d_surface
*surface
)
1028 WINED3DLOCKED_RECT lock
;
1031 TRACE("surface %p.\n", surface
);
1033 /* Create a DIB section if there isn't a dc yet. */
1036 if (surface
->flags
& SFLAG_CLIENT
)
1038 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
1039 surface_release_client_storage(surface
);
1041 hr
= surface_create_dib_section(surface
);
1043 return WINED3DERR_INVALIDCALL
;
1045 /* Use the DIB section from now on if we are not using a PBO. */
1046 if (!(surface
->flags
& SFLAG_PBO
))
1047 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1050 /* Map the surface. */
1051 hr
= wined3d_surface_map(surface
, &lock
, NULL
, 0);
1053 ERR("Map failed, hr %#x.\n", hr
);
1055 /* Sync the DIB with the PBO. This can't be done earlier because Map()
1056 * activates the allocatedMemory. */
1057 if (surface
->flags
& SFLAG_PBO
)
1058 memcpy(surface
->dib
.bitmap_data
, surface
->resource
.allocatedMemory
, surface
->resource
.size
);
1063 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
1065 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
1067 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
1072 static void wined3d_surface_depth_blt_fbo(struct wined3d_device
*device
, struct wined3d_surface
*src_surface
,
1073 const RECT
*src_rect
, struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
)
1075 const struct wined3d_gl_info
*gl_info
;
1076 struct wined3d_context
*context
;
1077 DWORD src_mask
, dst_mask
;
1080 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n",
1081 device
, src_surface
, wine_dbgstr_rect(src_rect
),
1082 dst_surface
, wine_dbgstr_rect(dst_rect
));
1084 src_mask
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1085 dst_mask
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1087 if (src_mask
!= dst_mask
)
1089 ERR("Incompatible formats %s and %s.\n",
1090 debug_d3dformat(src_surface
->resource
.format
->id
),
1091 debug_d3dformat(dst_surface
->resource
.format
->id
));
1097 ERR("Not a depth / stencil format: %s.\n",
1098 debug_d3dformat(src_surface
->resource
.format
->id
));
1103 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
1104 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
1105 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
1106 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
1108 /* Make sure the locations are up-to-date. Loading the destination
1109 * surface isn't required if the entire surface is overwritten. */
1110 surface_load_location(src_surface
, SFLAG_INTEXTURE
, NULL
);
1111 if (!surface_is_full_rect(dst_surface
, dst_rect
))
1112 surface_load_location(dst_surface
, SFLAG_INTEXTURE
, NULL
);
1114 context
= context_acquire(device
, NULL
);
1115 if (!context
->valid
)
1117 context_release(context
);
1118 WARN("Invalid context, skipping blit.\n");
1122 gl_info
= context
->gl_info
;
1126 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, SFLAG_INTEXTURE
);
1127 glReadBuffer(GL_NONE
);
1128 checkGLcall("glReadBuffer()");
1129 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1131 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, SFLAG_INTEXTURE
);
1132 context_set_draw_buffer(context
, GL_NONE
);
1133 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1135 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
1137 glDepthMask(GL_TRUE
);
1138 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
1140 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
1142 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
1144 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
1145 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE
));
1148 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
1151 glDisable(GL_SCISSOR_TEST
);
1152 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
1154 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
1155 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
1156 checkGLcall("glBlitFramebuffer()");
1160 if (wined3d_settings
.strict_draw_ordering
)
1161 wglFlush(); /* Flush to ensure ordering across contexts. */
1163 context_release(context
);
1166 /* Blit between surface locations. Onscreen on different swapchains is not supported.
1167 * Depth / stencil is not supported. */
1168 static void surface_blt_fbo(struct wined3d_device
*device
, const WINED3DTEXTUREFILTERTYPE filter
,
1169 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
1170 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
1172 const struct wined3d_gl_info
*gl_info
;
1173 struct wined3d_context
*context
;
1174 RECT src_rect
, dst_rect
;
1178 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
1179 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1180 src_surface
, debug_surflocation(src_location
), wine_dbgstr_rect(src_rect_in
));
1181 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1182 dst_surface
, debug_surflocation(dst_location
), wine_dbgstr_rect(dst_rect_in
));
1184 src_rect
= *src_rect_in
;
1185 dst_rect
= *dst_rect_in
;
1189 case WINED3DTEXF_LINEAR
:
1190 gl_filter
= GL_LINEAR
;
1194 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
1195 case WINED3DTEXF_NONE
:
1196 case WINED3DTEXF_POINT
:
1197 gl_filter
= GL_NEAREST
;
1201 /* Resolve the source surface first if needed. */
1202 if (src_location
== SFLAG_INRB_MULTISAMPLE
1203 && (src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
1204 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
1205 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
1206 src_location
= SFLAG_INRB_RESOLVED
;
1208 /* Make sure the locations are up-to-date. Loading the destination
1209 * surface isn't required if the entire surface is overwritten. (And is
1210 * in fact harmful if we're being called by surface_load_location() with
1211 * the purpose of loading the destination surface.) */
1212 surface_load_location(src_surface
, src_location
, NULL
);
1213 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
1214 surface_load_location(dst_surface
, dst_location
, NULL
);
1216 if (src_location
== SFLAG_INDRAWABLE
) context
= context_acquire(device
, src_surface
);
1217 else if (dst_location
== SFLAG_INDRAWABLE
) context
= context_acquire(device
, dst_surface
);
1218 else context
= context_acquire(device
, NULL
);
1220 if (!context
->valid
)
1222 context_release(context
);
1223 WARN("Invalid context, skipping blit.\n");
1227 gl_info
= context
->gl_info
;
1229 if (src_location
== SFLAG_INDRAWABLE
)
1231 TRACE("Source surface %p is onscreen.\n", src_surface
);
1232 buffer
= surface_get_gl_buffer(src_surface
);
1233 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
1237 TRACE("Source surface %p is offscreen.\n", src_surface
);
1238 buffer
= GL_COLOR_ATTACHMENT0
;
1242 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
1243 glReadBuffer(buffer
);
1244 checkGLcall("glReadBuffer()");
1245 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1248 if (dst_location
== SFLAG_INDRAWABLE
)
1250 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
1251 buffer
= surface_get_gl_buffer(dst_surface
);
1252 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
1256 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
1257 buffer
= GL_COLOR_ATTACHMENT0
;
1261 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
1262 context_set_draw_buffer(context
, buffer
);
1263 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1264 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
1266 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
1267 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
1268 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1
));
1269 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2
));
1270 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3
));
1272 glDisable(GL_SCISSOR_TEST
);
1273 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
1275 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
1276 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
1277 checkGLcall("glBlitFramebuffer()");
1281 if (wined3d_settings
.strict_draw_ordering
1282 || (dst_location
== SFLAG_INDRAWABLE
1283 && dst_surface
->container
.u
.swapchain
->front_buffer
== dst_surface
))
1286 context_release(context
);
1289 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
1290 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
1291 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
1293 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
1296 /* Source and/or destination need to be on the GL side */
1297 if (src_pool
== WINED3DPOOL_SYSTEMMEM
|| dst_pool
== WINED3DPOOL_SYSTEMMEM
)
1302 case WINED3D_BLIT_OP_COLOR_BLIT
:
1303 if (!((src_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
1305 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
1309 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1310 if (!(src_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1312 if (!(dst_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1320 if (!(src_format
->id
== dst_format
->id
1321 || (is_identity_fixup(src_format
->color_fixup
)
1322 && is_identity_fixup(dst_format
->color_fixup
))))
1328 /* This function checks if the primary render target uses the 8bit paletted format. */
1329 static BOOL
primary_render_target_is_p8(const struct wined3d_device
*device
)
1331 if (device
->fb
.render_targets
&& device
->fb
.render_targets
[0])
1333 const struct wined3d_surface
*render_target
= device
->fb
.render_targets
[0];
1334 if ((render_target
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
1335 && (render_target
->resource
.format
->id
== WINED3DFMT_P8_UINT
))
1341 static BOOL
surface_convert_color_to_float(const struct wined3d_surface
*surface
,
1342 DWORD color
, WINED3DCOLORVALUE
*float_color
)
1344 const struct wined3d_format
*format
= surface
->resource
.format
;
1345 const struct wined3d_device
*device
= surface
->resource
.device
;
1349 case WINED3DFMT_P8_UINT
:
1350 if (surface
->palette
)
1352 float_color
->r
= surface
->palette
->palents
[color
].peRed
/ 255.0f
;
1353 float_color
->g
= surface
->palette
->palents
[color
].peGreen
/ 255.0f
;
1354 float_color
->b
= surface
->palette
->palents
[color
].peBlue
/ 255.0f
;
1358 float_color
->r
= 0.0f
;
1359 float_color
->g
= 0.0f
;
1360 float_color
->b
= 0.0f
;
1362 float_color
->a
= primary_render_target_is_p8(device
) ? color
/ 255.0f
: 1.0f
;
1365 case WINED3DFMT_B5G6R5_UNORM
:
1366 float_color
->r
= ((color
>> 11) & 0x1f) / 31.0f
;
1367 float_color
->g
= ((color
>> 5) & 0x3f) / 63.0f
;
1368 float_color
->b
= (color
& 0x1f) / 31.0f
;
1369 float_color
->a
= 1.0f
;
1372 case WINED3DFMT_B8G8R8_UNORM
:
1373 case WINED3DFMT_B8G8R8X8_UNORM
:
1374 float_color
->r
= D3DCOLOR_R(color
);
1375 float_color
->g
= D3DCOLOR_G(color
);
1376 float_color
->b
= D3DCOLOR_B(color
);
1377 float_color
->a
= 1.0f
;
1380 case WINED3DFMT_B8G8R8A8_UNORM
:
1381 float_color
->r
= D3DCOLOR_R(color
);
1382 float_color
->g
= D3DCOLOR_G(color
);
1383 float_color
->b
= D3DCOLOR_B(color
);
1384 float_color
->a
= D3DCOLOR_A(color
);
1388 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1395 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1397 const struct wined3d_format
*format
= surface
->resource
.format
;
1401 case WINED3DFMT_S1_UINT_D15_UNORM
:
1402 *float_depth
= depth
/ (float)0x00007fff;
1405 case WINED3DFMT_D16_UNORM
:
1406 *float_depth
= depth
/ (float)0x0000ffff;
1409 case WINED3DFMT_D24_UNORM_S8_UINT
:
1410 case WINED3DFMT_X8D24_UNORM
:
1411 *float_depth
= depth
/ (float)0x00ffffff;
1414 case WINED3DFMT_D32_UNORM
:
1415 *float_depth
= depth
/ (float)0xffffffff;
1419 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1426 /* Do not call while under the GL lock. */
1427 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1429 const struct wined3d_resource
*resource
= &surface
->resource
;
1430 struct wined3d_device
*device
= resource
->device
;
1431 const struct blit_shader
*blitter
;
1433 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_FILL
,
1434 NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
);
1437 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1438 return WINED3DERR_INVALIDCALL
;
1441 return blitter
->depth_fill(device
, surface
, rect
, depth
);
1444 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
1445 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
)
1447 struct wined3d_device
*device
= src_surface
->resource
.device
;
1449 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1450 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1451 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1452 return WINED3DERR_INVALIDCALL
;
1454 wined3d_surface_depth_blt_fbo(device
, src_surface
, src_rect
, dst_surface
, dst_rect
);
1456 surface_modify_ds_location(dst_surface
, SFLAG_DS_OFFSCREEN
,
1457 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1458 surface_modify_location(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
1463 /* Do not call while under the GL lock. */
1464 HRESULT CDECL
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
,
1465 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD flags
,
1466 const WINEDDBLTFX
*fx
, WINED3DTEXTUREFILTERTYPE filter
)
1468 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
1469 struct wined3d_device
*device
= dst_surface
->resource
.device
;
1470 DWORD src_ds_flags
, dst_ds_flags
;
1471 RECT src_rect
, dst_rect
;
1473 static const DWORD simple_blit
= WINEDDBLT_ASYNC
1474 | WINEDDBLT_COLORFILL
1476 | WINEDDBLT_DEPTHFILL
1477 | WINEDDBLT_DONOTWAIT
;
1479 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1480 dst_surface
, wine_dbgstr_rect(dst_rect_in
), src_surface
, wine_dbgstr_rect(src_rect_in
),
1481 flags
, fx
, debug_d3dtexturefiltertype(filter
));
1482 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
1484 if ((dst_surface
->flags
& SFLAG_LOCKED
) || (src_surface
&& (src_surface
->flags
& SFLAG_LOCKED
)))
1486 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
1487 return WINEDDERR_SURFACEBUSY
;
1490 surface_get_rect(dst_surface
, dst_rect_in
, &dst_rect
);
1492 if (dst_rect
.left
>= dst_rect
.right
|| dst_rect
.top
>= dst_rect
.bottom
1493 || dst_rect
.left
> dst_surface
->resource
.width
|| dst_rect
.left
< 0
1494 || dst_rect
.top
> dst_surface
->resource
.height
|| dst_rect
.top
< 0
1495 || dst_rect
.right
> dst_surface
->resource
.width
|| dst_rect
.right
< 0
1496 || dst_rect
.bottom
> dst_surface
->resource
.height
|| dst_rect
.bottom
< 0)
1498 /* The destination rect can be out of bounds on the condition
1499 * that a clipper is set for the surface. */
1500 if (dst_surface
->clipper
)
1501 FIXME("Blit clipping not implemented.\n");
1503 WARN("The application gave us a bad destination rectangle without a clipper set.\n");
1504 return WINEDDERR_INVALIDRECT
;
1509 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
1511 if (src_rect
.left
>= src_rect
.right
|| src_rect
.top
>= src_rect
.bottom
1512 || src_rect
.left
> src_surface
->resource
.width
|| src_rect
.left
< 0
1513 || src_rect
.top
> src_surface
->resource
.height
|| src_rect
.top
< 0
1514 || src_rect
.right
> src_surface
->resource
.width
|| src_rect
.right
< 0
1515 || src_rect
.bottom
> src_surface
->resource
.height
|| src_rect
.bottom
< 0)
1517 WARN("Application gave us bad source rectangle for Blt.\n");
1518 return WINEDDERR_INVALIDRECT
;
1523 memset(&src_rect
, 0, sizeof(src_rect
));
1526 if (!fx
|| !(fx
->dwDDFX
))
1527 flags
&= ~WINEDDBLT_DDFX
;
1529 if (flags
& WINEDDBLT_WAIT
)
1530 flags
&= ~WINEDDBLT_WAIT
;
1532 if (flags
& WINEDDBLT_ASYNC
)
1534 static unsigned int once
;
1537 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
1538 flags
&= ~WINEDDBLT_ASYNC
;
1541 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
1542 if (flags
& WINEDDBLT_DONOTWAIT
)
1544 static unsigned int once
;
1547 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
1548 flags
&= ~WINEDDBLT_DONOTWAIT
;
1551 if (!device
->d3d_initialized
)
1553 WARN("D3D not initialized, using fallback.\n");
1557 if (flags
& ~simple_blit
)
1559 WARN("Using fallback for complex blit (%#x).\n", flags
);
1563 if (src_surface
&& src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
1564 src_swapchain
= src_surface
->container
.u
.swapchain
;
1566 src_swapchain
= NULL
;
1568 if (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
1569 dst_swapchain
= dst_surface
->container
.u
.swapchain
;
1571 dst_swapchain
= NULL
;
1573 /* This isn't strictly needed. FBO blits for example could deal with
1574 * cross-swapchain blits by first downloading the source to a texture
1575 * before switching to the destination context. We just have this here to
1576 * not have to deal with the issue, since cross-swapchain blits should be
1578 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
1580 FIXME("Using fallback for cross-swapchain blit.\n");
1584 dst_ds_flags
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1586 src_ds_flags
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1590 if (src_ds_flags
|| dst_ds_flags
)
1592 if (flags
& WINEDDBLT_DEPTHFILL
)
1596 TRACE("Depth fill.\n");
1598 if (!surface_convert_depth_to_float(dst_surface
, fx
->u5
.dwFillDepth
, &depth
))
1599 return WINED3DERR_INVALIDCALL
;
1601 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, &dst_rect
, depth
)))
1606 /* Accessing depth / stencil surfaces is supposed to fail while in
1607 * a scene, except for fills, which seem to work. */
1608 if (device
->inScene
)
1610 WARN("Rejecting depth / stencil access while in scene.\n");
1611 return WINED3DERR_INVALIDCALL
;
1614 if (src_ds_flags
!= dst_ds_flags
)
1616 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
1617 return WINED3DERR_INVALIDCALL
;
1620 if (src_rect
.top
|| src_rect
.left
1621 || src_rect
.bottom
!= src_surface
->resource
.height
1622 || src_rect
.right
!= src_surface
->resource
.width
)
1624 WARN("Rejecting depth / stencil blit with invalid source rect %s.\n",
1625 wine_dbgstr_rect(&src_rect
));
1626 return WINED3DERR_INVALIDCALL
;
1629 if (dst_rect
.top
|| dst_rect
.left
1630 || dst_rect
.bottom
!= dst_surface
->resource
.height
1631 || dst_rect
.right
!= dst_surface
->resource
.width
)
1633 WARN("Rejecting depth / stencil blit with invalid destination rect %s.\n",
1634 wine_dbgstr_rect(&src_rect
));
1635 return WINED3DERR_INVALIDCALL
;
1638 if (src_surface
->resource
.height
!= dst_surface
->resource
.height
1639 || src_surface
->resource
.width
!= dst_surface
->resource
.width
)
1641 WARN("Rejecting depth / stencil blit with mismatched surface sizes.\n");
1642 return WINED3DERR_INVALIDCALL
;
1645 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
1651 if (flags
& WINEDDBLT_COLORFILL
)
1653 WINED3DCOLORVALUE color
;
1655 TRACE("Color fill.\n");
1657 if (!surface_convert_color_to_float(dst_surface
, fx
->u5
.dwFillColor
, &color
))
1660 if (SUCCEEDED(surface_color_fill(dst_surface
, &dst_rect
, &color
)))
1665 TRACE("Color blit.\n");
1667 /* Use present for back -> front blits. The idea behind this is
1668 * that present is potentially faster than a blit, in particular
1669 * when FBO blits aren't available. Some ddraw applications like
1670 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
1671 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
1672 * applications can't blit directly to the frontbuffer. */
1673 if (dst_swapchain
&& dst_swapchain
->back_buffers
1674 && dst_surface
== dst_swapchain
->front_buffer
1675 && src_surface
== dst_swapchain
->back_buffers
[0])
1677 WINED3DSWAPEFFECT swap_effect
= dst_swapchain
->presentParms
.SwapEffect
;
1679 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
1681 /* Set the swap effect to COPY, we don't want the backbuffer
1682 * to become undefined. */
1683 dst_swapchain
->presentParms
.SwapEffect
= WINED3DSWAPEFFECT_COPY
;
1684 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, NULL
, 0);
1685 dst_swapchain
->presentParms
.SwapEffect
= swap_effect
;
1690 if (fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
1691 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1692 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1694 TRACE("Using FBO blit.\n");
1696 surface_blt_fbo(device
, filter
,
1697 src_surface
, src_surface
->draw_binding
, &src_rect
,
1698 dst_surface
, dst_surface
->draw_binding
, &dst_rect
);
1699 surface_modify_location(dst_surface
, dst_surface
->draw_binding
, TRUE
);
1703 if (arbfp_blit
.blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
1704 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1705 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1707 TRACE("Using arbfp blit.\n");
1709 if (SUCCEEDED(arbfp_blit_surface(device
, filter
, src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
1717 /* Special cases for render targets. */
1718 if ((dst_surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
1719 || (src_surface
&& (src_surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)))
1721 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface
, &dst_rect
,
1722 src_surface
, &src_rect
, flags
, fx
, filter
)))
1728 /* For the rest call the X11 surface implementation. For render targets
1729 * this should be implemented OpenGL accelerated in BltOverride, other
1730 * blits are rather rare. */
1731 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
1734 /* Do not call while under the GL lock. */
1735 HRESULT CDECL
wined3d_surface_bltfast(struct wined3d_surface
*dst_surface
, DWORD dst_x
, DWORD dst_y
,
1736 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD trans
)
1738 RECT src_rect
, dst_rect
;
1741 TRACE("dst_surface %p, dst_x %u, dst_y %u, src_surface %p, src_rect_in %s, trans %#x.\n",
1742 dst_surface
, dst_x
, dst_y
, src_surface
, wine_dbgstr_rect(src_rect_in
), trans
);
1744 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
1746 dst_rect
.left
= dst_x
;
1747 dst_rect
.top
= dst_y
;
1748 dst_rect
.right
= dst_x
+ src_rect
.right
- src_rect
.left
;
1749 dst_rect
.bottom
= dst_y
+ src_rect
.bottom
- src_rect
.top
;
1751 if (trans
& WINEDDBLTFAST_SRCCOLORKEY
)
1752 flags
|= WINEDDBLT_KEYSRC
;
1753 if (trans
& WINEDDBLTFAST_DESTCOLORKEY
)
1754 flags
|= WINEDDBLT_KEYDEST
;
1755 if (trans
& WINEDDBLTFAST_WAIT
)
1756 flags
|= WINEDDBLT_WAIT
;
1757 if (trans
& WINEDDBLTFAST_DONOTWAIT
)
1758 flags
|= WINEDDBLT_DONOTWAIT
;
1760 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, NULL
, WINED3DTEXF_POINT
);
1763 /* Context activation is done by the caller. */
1764 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1766 if (!surface
->resource
.heapMemory
)
1768 surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
+ RESOURCE_ALIGNMENT
);
1769 surface
->resource
.allocatedMemory
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
1770 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
1774 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
1775 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
1776 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0,
1777 surface
->resource
.size
, surface
->resource
.allocatedMemory
));
1778 checkGLcall("glGetBufferSubDataARB");
1779 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
1780 checkGLcall("glDeleteBuffersARB");
1784 surface
->flags
&= ~SFLAG_PBO
;
1787 /* Do not call while under the GL lock. */
1788 static void surface_unload(struct wined3d_resource
*resource
)
1790 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1791 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1792 struct wined3d_device
*device
= resource
->device
;
1793 const struct wined3d_gl_info
*gl_info
;
1794 struct wined3d_context
*context
;
1796 TRACE("surface %p.\n", surface
);
1798 if (resource
->pool
== WINED3DPOOL_DEFAULT
)
1800 /* Default pool resources are supposed to be destroyed before Reset is called.
1801 * Implicit resources stay however. So this means we have an implicit render target
1802 * or depth stencil. The content may be destroyed, but we still have to tear down
1803 * opengl resources, so we cannot leave early.
1805 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1806 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1807 * or the depth stencil into an FBO the texture or render buffer will be removed
1808 * and all flags get lost
1810 surface_init_sysmem(surface
);
1814 /* Load the surface into system memory */
1815 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
1816 surface_modify_location(surface
, surface
->draw_binding
, FALSE
);
1818 surface_modify_location(surface
, SFLAG_INTEXTURE
, FALSE
);
1819 surface_modify_location(surface
, SFLAG_INSRGBTEX
, FALSE
);
1820 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
1822 context
= context_acquire(device
, NULL
);
1823 gl_info
= context
->gl_info
;
1825 /* Destroy PBOs, but load them into real sysmem before */
1826 if (surface
->flags
& SFLAG_PBO
)
1827 surface_remove_pbo(surface
, gl_info
);
1829 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1830 * all application-created targets the application has to release the surface
1831 * before calling _Reset
1833 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1836 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1838 list_remove(&entry
->entry
);
1839 HeapFree(GetProcessHeap(), 0, entry
);
1841 list_init(&surface
->renderbuffers
);
1842 surface
->current_renderbuffer
= NULL
;
1846 /* If we're in a texture, the texture name belongs to the texture.
1847 * Otherwise, destroy it. */
1848 if (surface
->container
.type
!= WINED3D_CONTAINER_TEXTURE
)
1850 glDeleteTextures(1, &surface
->texture_name
);
1851 surface
->texture_name
= 0;
1852 glDeleteTextures(1, &surface
->texture_name_srgb
);
1853 surface
->texture_name_srgb
= 0;
1855 if (surface
->rb_multisample
)
1857 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
1858 surface
->rb_multisample
= 0;
1860 if (surface
->rb_resolved
)
1862 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
1863 surface
->rb_resolved
= 0;
1868 context_release(context
);
1870 resource_unload(resource
);
1873 static const struct wined3d_resource_ops surface_resource_ops
=
1878 static const struct wined3d_surface_ops surface_ops
=
1880 surface_private_setup
,
1882 surface_realize_palette
,
1883 surface_draw_overlay
,
1890 /*****************************************************************************
1891 * Initializes the GDI surface, aka creates the DIB section we render to
1892 * The DIB section creation is done by calling GetDC, which will create the
1893 * section and releasing the dc to allow the app to use it. The dib section
1894 * will stay until the surface is released
1896 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1897 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1898 * avoid confusion in the shared surface code.
1901 * WINED3D_OK on success
1902 * The return values of called methods on failure
1904 *****************************************************************************/
1905 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1909 TRACE("surface %p.\n", surface
);
1911 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1913 ERR("Overlays not yet supported by GDI surfaces.\n");
1914 return WINED3DERR_INVALIDCALL
;
1917 /* Sysmem textures have memory already allocated - release it,
1918 * this avoids an unnecessary memcpy. */
1919 hr
= surface_create_dib_section(surface
);
1922 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
1923 surface
->resource
.heapMemory
= NULL
;
1924 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1927 /* We don't mind the nonpow2 stuff in GDI. */
1928 surface
->pow2Width
= surface
->resource
.width
;
1929 surface
->pow2Height
= surface
->resource
.height
;
1934 static void surface_gdi_cleanup(struct wined3d_surface
*surface
)
1936 TRACE("surface %p.\n", surface
);
1938 if (surface
->flags
& SFLAG_DIBSECTION
)
1940 /* Release the DC. */
1941 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
1942 DeleteDC(surface
->hDC
);
1943 /* Release the DIB section. */
1944 DeleteObject(surface
->dib
.DIBsection
);
1945 surface
->dib
.bitmap_data
= NULL
;
1946 surface
->resource
.allocatedMemory
= NULL
;
1949 if (surface
->flags
& SFLAG_USERPTR
)
1950 wined3d_surface_set_mem(surface
, NULL
);
1951 if (surface
->overlay_dest
)
1952 list_remove(&surface
->overlay_entry
);
1954 HeapFree(GetProcessHeap(), 0, surface
->palette9
);
1956 resource_cleanup(&surface
->resource
);
1959 static void gdi_surface_realize_palette(struct wined3d_surface
*surface
)
1961 struct wined3d_palette
*palette
= surface
->palette
;
1963 TRACE("surface %p.\n", surface
);
1965 if (!palette
) return;
1967 if (surface
->flags
& SFLAG_DIBSECTION
)
1972 TRACE("Updating the DC's palette.\n");
1974 for (i
= 0; i
< 256; ++i
)
1976 col
[i
].rgbRed
= palette
->palents
[i
].peRed
;
1977 col
[i
].rgbGreen
= palette
->palents
[i
].peGreen
;
1978 col
[i
].rgbBlue
= palette
->palents
[i
].peBlue
;
1979 col
[i
].rgbReserved
= 0;
1981 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
1984 /* Update the image because of the palette change. Some games like e.g.
1985 * Red Alert call SetEntries a lot to implement fading. */
1986 /* Tell the swapchain to update the screen. */
1987 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
1989 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
1990 if (surface
== swapchain
->front_buffer
)
1992 x11_copy_to_screen(swapchain
, NULL
);
1997 static HRESULT
gdi_surface_draw_overlay(struct wined3d_surface
*surface
)
1999 FIXME("GDI surfaces can't draw overlays yet.\n");
2003 static void gdi_surface_preload(struct wined3d_surface
*surface
)
2005 TRACE("surface %p.\n", surface
);
2007 ERR("Preloading GDI surfaces is not supported.\n");
2010 static void gdi_surface_map(struct wined3d_surface
*surface
, const RECT
*rect
, DWORD flags
)
2012 TRACE("surface %p, rect %s, flags %#x.\n",
2013 surface
, wine_dbgstr_rect(rect
), flags
);
2015 if (!surface
->resource
.allocatedMemory
)
2017 /* This happens on gdi surfaces if the application set a user pointer
2018 * and resets it. Recreate the DIB section. */
2019 surface_create_dib_section(surface
);
2020 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
2024 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
2026 TRACE("surface %p.\n", surface
);
2028 /* Tell the swapchain to update the screen. */
2029 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
2031 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
2032 if (surface
== swapchain
->front_buffer
)
2034 x11_copy_to_screen(swapchain
, &surface
->lockedRect
);
2038 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
2041 static HRESULT
gdi_surface_getdc(struct wined3d_surface
*surface
)
2043 WINED3DLOCKED_RECT lock
;
2046 TRACE("surface %p.\n", surface
);
2048 /* Should have a DIB section already. */
2049 if (!(surface
->flags
& SFLAG_DIBSECTION
))
2051 WARN("DC not supported on this surface\n");
2052 return WINED3DERR_INVALIDCALL
;
2055 /* Map the surface. */
2056 hr
= wined3d_surface_map(surface
, &lock
, NULL
, 0);
2058 ERR("Map failed, hr %#x.\n", hr
);
2063 static const struct wined3d_surface_ops gdi_surface_ops
=
2065 gdi_surface_private_setup
,
2066 surface_gdi_cleanup
,
2067 gdi_surface_realize_palette
,
2068 gdi_surface_draw_overlay
,
2069 gdi_surface_preload
,
2075 void surface_set_texture_name(struct wined3d_surface
*surface
, GLuint new_name
, BOOL srgb
)
2080 TRACE("surface %p, new_name %u, srgb %#x.\n", surface
, new_name
, srgb
);
2084 name
= &surface
->texture_name_srgb
;
2085 flag
= SFLAG_INSRGBTEX
;
2089 name
= &surface
->texture_name
;
2090 flag
= SFLAG_INTEXTURE
;
2093 if (!*name
&& new_name
)
2095 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
2096 * surface has no texture name yet. See if we can get rid of this. */
2097 if (surface
->flags
& flag
)
2098 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag
));
2099 surface_modify_location(surface
, flag
, FALSE
);
2103 surface_force_reload(surface
);
2106 void surface_set_texture_target(struct wined3d_surface
*surface
, GLenum target
)
2108 TRACE("surface %p, target %#x.\n", surface
, target
);
2110 if (surface
->texture_target
!= target
)
2112 if (target
== GL_TEXTURE_RECTANGLE_ARB
)
2114 surface
->flags
&= ~SFLAG_NORMCOORD
;
2116 else if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
2118 surface
->flags
|= SFLAG_NORMCOORD
;
2121 surface
->texture_target
= target
;
2122 surface_force_reload(surface
);
2125 /* Context activation is done by the caller. */
2126 void surface_bind(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
2128 TRACE("surface %p, context %p, srgb %#x.\n", surface
, context
, srgb
);
2130 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
2132 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
2134 TRACE("Passing to container (%p).\n", texture
);
2135 texture
->texture_ops
->texture_bind(texture
, context
, srgb
);
2139 if (surface
->texture_level
)
2141 ERR("Standalone surface %p is non-zero texture level %u.\n",
2142 surface
, surface
->texture_level
);
2146 ERR("Trying to bind standalone surface %p as sRGB.\n", surface
);
2150 if (!surface
->texture_name
)
2152 glGenTextures(1, &surface
->texture_name
);
2153 checkGLcall("glGenTextures");
2155 TRACE("Surface %p given name %u.\n", surface
, surface
->texture_name
);
2157 context_bind_texture(context
, surface
->texture_target
, surface
->texture_name
);
2158 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2159 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2160 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
2161 glTexParameteri(surface
->texture_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2162 glTexParameteri(surface
->texture_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2163 checkGLcall("glTexParameteri");
2167 context_bind_texture(context
, surface
->texture_target
, surface
->texture_name
);
2174 /* This call just downloads data, the caller is responsible for binding the
2175 * correct texture. */
2176 /* Context activation is done by the caller. */
2177 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
2179 const struct wined3d_format
*format
= surface
->resource
.format
;
2181 /* Only support read back of converted P8 surfaces. */
2182 if (surface
->flags
& SFLAG_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
2184 FIXME("Readback conversion not supported for format %s.\n", debug_d3dformat(format
->id
));
2190 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
2192 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2193 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
,
2194 surface
->resource
.allocatedMemory
);
2196 if (surface
->flags
& SFLAG_PBO
)
2198 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
2199 checkGLcall("glBindBufferARB");
2200 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
, surface
->texture_level
, NULL
));
2201 checkGLcall("glGetCompressedTexImageARB");
2202 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
2203 checkGLcall("glBindBufferARB");
2207 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
,
2208 surface
->texture_level
, surface
->resource
.allocatedMemory
));
2209 checkGLcall("glGetCompressedTexImageARB");
2217 GLenum gl_format
= format
->glFormat
;
2218 GLenum gl_type
= format
->glType
;
2222 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
2223 if (format
->id
== WINED3DFMT_P8_UINT
&& primary_render_target_is_p8(surface
->resource
.device
))
2225 gl_format
= GL_ALPHA
;
2226 gl_type
= GL_UNSIGNED_BYTE
;
2229 if (surface
->flags
& SFLAG_NONPOW2
)
2231 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
2232 src_pitch
= format
->byte_count
* surface
->pow2Width
;
2233 dst_pitch
= wined3d_surface_get_pitch(surface
);
2234 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
2235 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
2239 mem
= surface
->resource
.allocatedMemory
;
2242 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2243 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
2245 if (surface
->flags
& SFLAG_PBO
)
2247 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
2248 checkGLcall("glBindBufferARB");
2250 glGetTexImage(surface
->texture_target
, surface
->texture_level
, gl_format
, gl_type
, NULL
);
2251 checkGLcall("glGetTexImage");
2253 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
2254 checkGLcall("glBindBufferARB");
2258 glGetTexImage(surface
->texture_target
, surface
->texture_level
, gl_format
, gl_type
, mem
);
2259 checkGLcall("glGetTexImage");
2263 if (surface
->flags
& SFLAG_NONPOW2
)
2265 const BYTE
*src_data
;
2269 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2270 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2271 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2273 * We're doing this...
2275 * instead of boxing the texture :
2276 * |<-texture width ->| -->pow2width| /\
2277 * |111111111111111111| | |
2278 * |222 Texture 222222| boxed empty | texture height
2279 * |3333 Data 33333333| | |
2280 * |444444444444444444| | \/
2281 * ----------------------------------- |
2282 * | boxed empty | boxed empty | pow2height
2284 * -----------------------------------
2287 * we're repacking the data to the expected texture width
2289 * |<-texture width ->| -->pow2width| /\
2290 * |111111111111111111222222222222222| |
2291 * |222333333333333333333444444444444| texture height
2295 * | empty | pow2height
2297 * -----------------------------------
2301 * |<-texture width ->| /\
2302 * |111111111111111111|
2303 * |222222222222222222|texture height
2304 * |333333333333333333|
2305 * |444444444444444444| \/
2306 * --------------------
2308 * this also means that any references to allocatedMemory should work with the data as if were a
2309 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2311 * internally the texture is still stored in a boxed format so any references to textureName will
2312 * get a boxed texture with width pow2width and not a texture of width resource.width.
2314 * Performance should not be an issue, because applications normally do not lock the surfaces when
2315 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2316 * and doesn't have to be re-read. */
2318 dst_data
= surface
->resource
.allocatedMemory
;
2319 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_pitch
);
2320 for (y
= 1; y
< surface
->resource
.height
; ++y
)
2322 /* skip the first row */
2323 src_data
+= src_pitch
;
2324 dst_data
+= dst_pitch
;
2325 memcpy(dst_data
, src_data
, dst_pitch
);
2328 HeapFree(GetProcessHeap(), 0, mem
);
2332 /* Surface has now been downloaded */
2333 surface
->flags
|= SFLAG_INSYSMEM
;
2336 /* This call just uploads data, the caller is responsible for binding the
2337 * correct texture. */
2338 /* Context activation is done by the caller. */
2339 void surface_upload_data(const struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
2340 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_w
, const POINT
*dst_point
,
2341 BOOL srgb
, const struct wined3d_bo_address
*data
)
2343 UINT update_w
= src_rect
->right
- src_rect
->left
;
2344 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
2346 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_w %u, dst_point %p, srgb %#x, data {%#x:%p}.\n",
2347 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_w
,
2348 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
2350 if (format
->heightscale
!= 1.0f
&& format
->heightscale
!= 0.0f
)
2351 update_h
*= format
->heightscale
;
2355 if (data
->buffer_object
)
2357 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, data
->buffer_object
));
2358 checkGLcall("glBindBufferARB");
2361 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
2363 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1);
2364 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
2365 UINT src_pitch
= wined3d_format_calculate_size(format
, 1, src_w
, 1);
2366 const BYTE
*addr
= data
->addr
;
2369 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
2370 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
2373 internal
= format
->glGammaInternal
;
2374 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
2375 internal
= format
->rtInternal
;
2377 internal
= format
->glInternal
;
2379 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
2380 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
2381 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
2383 if (row_length
== src_pitch
)
2385 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
2386 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
2392 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
2393 * can't use the unpack row length like below. */
2394 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
2396 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
2397 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
2398 y
+= format
->block_height
;
2402 checkGLcall("glCompressedTexSubImage2DARB");
2406 const BYTE
*addr
= data
->addr
;
2408 addr
+= src_rect
->top
* src_w
* format
->byte_count
;
2409 addr
+= src_rect
->left
* format
->byte_count
;
2411 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
2412 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
2413 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
2415 glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_w
);
2416 glTexSubImage2D(surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
2417 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
2418 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
2419 checkGLcall("glTexSubImage2D");
2422 if (data
->buffer_object
)
2424 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
2425 checkGLcall("glBindBufferARB");
2430 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
2432 struct wined3d_device
*device
= surface
->resource
.device
;
2435 for (i
= 0; i
< device
->context_count
; ++i
)
2437 context_surface_update(device
->contexts
[i
], surface
);
2442 /* This call just allocates the texture, the caller is responsible for binding
2443 * the correct texture. */
2444 /* Context activation is done by the caller. */
2445 static void surface_allocate_surface(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
2446 const struct wined3d_format
*format
, BOOL srgb
)
2448 BOOL enable_client_storage
= FALSE
;
2449 GLsizei width
= surface
->pow2Width
;
2450 GLsizei height
= surface
->pow2Height
;
2451 const BYTE
*mem
= NULL
;
2456 internal
= format
->glGammaInternal
;
2458 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
2460 internal
= format
->rtInternal
;
2464 internal
= format
->glInternal
;
2467 if (format
->heightscale
!= 1.0f
&& format
->heightscale
!= 0.0f
) height
*= format
->heightscale
;
2469 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",
2470 surface
, surface
->texture_target
, surface
->texture_level
, debug_d3dformat(format
->id
),
2471 internal
, width
, height
, format
->glFormat
, format
->glType
);
2475 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
2477 if (surface
->flags
& (SFLAG_NONPOW2
| SFLAG_DIBSECTION
| SFLAG_CONVERTED
)
2478 || !surface
->resource
.allocatedMemory
)
2480 /* In some cases we want to disable client storage.
2481 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2482 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2483 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2484 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2486 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2487 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2488 surface
->flags
&= ~SFLAG_CLIENT
;
2489 enable_client_storage
= TRUE
;
2493 surface
->flags
|= SFLAG_CLIENT
;
2495 /* Point OpenGL to our allocated texture memory. Do not use
2496 * resource.allocatedMemory here because it might point into a
2497 * PBO. Instead use heapMemory, but get the alignment right. */
2498 mem
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
2499 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
2503 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
&& mem
)
2505 GL_EXTCALL(glCompressedTexImage2DARB(surface
->texture_target
, surface
->texture_level
,
2506 internal
, width
, height
, 0, surface
->resource
.size
, mem
));
2507 checkGLcall("glCompressedTexImage2DARB");
2511 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
2512 internal
, width
, height
, 0, format
->glFormat
, format
->glType
, mem
);
2513 checkGLcall("glTexImage2D");
2516 if(enable_client_storage
) {
2517 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2518 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2523 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2524 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2525 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2526 /* GL locking is done by the caller */
2527 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
2529 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
2530 struct wined3d_renderbuffer_entry
*entry
;
2531 GLuint renderbuffer
= 0;
2532 unsigned int src_width
, src_height
;
2533 unsigned int width
, height
;
2535 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
2537 width
= rt
->pow2Width
;
2538 height
= rt
->pow2Height
;
2542 width
= surface
->pow2Width
;
2543 height
= surface
->pow2Height
;
2546 src_width
= surface
->pow2Width
;
2547 src_height
= surface
->pow2Height
;
2549 /* A depth stencil smaller than the render target is not valid */
2550 if (width
> src_width
|| height
> src_height
) return;
2552 /* Remove any renderbuffer set if the sizes match */
2553 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
2554 || (width
== src_width
&& height
== src_height
))
2556 surface
->current_renderbuffer
= NULL
;
2560 /* Look if we've already got a renderbuffer of the correct dimensions */
2561 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
2563 if (entry
->width
== width
&& entry
->height
== height
)
2565 renderbuffer
= entry
->id
;
2566 surface
->current_renderbuffer
= entry
;
2573 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
2574 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
2575 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
2576 surface
->resource
.format
->glInternal
, width
, height
);
2578 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
2579 entry
->width
= width
;
2580 entry
->height
= height
;
2581 entry
->id
= renderbuffer
;
2582 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
2584 surface
->current_renderbuffer
= entry
;
2587 checkGLcall("set_compatible_renderbuffer");
2590 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
2592 const struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
2594 TRACE("surface %p.\n", surface
);
2596 if (surface
->container
.type
!= WINED3D_CONTAINER_SWAPCHAIN
)
2598 ERR("Surface %p is not on a swapchain.\n", surface
);
2602 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
)
2604 if (swapchain
->render_to_fbo
)
2606 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2607 return GL_COLOR_ATTACHMENT0
;
2609 TRACE("Returning GL_BACK\n");
2612 else if (surface
== swapchain
->front_buffer
)
2614 TRACE("Returning GL_FRONT\n");
2618 FIXME("Higher back buffer, returning GL_BACK\n");
2622 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
2623 void surface_add_dirty_rect(struct wined3d_surface
*surface
, const WINED3DBOX
*dirty_rect
)
2625 TRACE("surface %p, dirty_rect %p.\n", surface
, dirty_rect
);
2627 if (!(surface
->flags
& SFLAG_INSYSMEM
) && (surface
->flags
& SFLAG_INTEXTURE
))
2628 /* No partial locking for textures yet. */
2629 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
2631 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
2634 surface
->dirtyRect
.left
= min(surface
->dirtyRect
.left
, dirty_rect
->Left
);
2635 surface
->dirtyRect
.top
= min(surface
->dirtyRect
.top
, dirty_rect
->Top
);
2636 surface
->dirtyRect
.right
= max(surface
->dirtyRect
.right
, dirty_rect
->Right
);
2637 surface
->dirtyRect
.bottom
= max(surface
->dirtyRect
.bottom
, dirty_rect
->Bottom
);
2641 surface
->dirtyRect
.left
= 0;
2642 surface
->dirtyRect
.top
= 0;
2643 surface
->dirtyRect
.right
= surface
->resource
.width
;
2644 surface
->dirtyRect
.bottom
= surface
->resource
.height
;
2647 /* if the container is a texture then mark it dirty. */
2648 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
2650 TRACE("Passing to container.\n");
2651 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
2655 HRESULT
surface_load(struct wined3d_surface
*surface
, BOOL srgb
)
2657 DWORD flag
= srgb
? SFLAG_INSRGBTEX
: SFLAG_INTEXTURE
;
2660 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
2662 if (surface
->resource
.pool
== WINED3DPOOL_SCRATCH
)
2664 ERR("Not supported on scratch surfaces.\n");
2665 return WINED3DERR_INVALIDCALL
;
2668 ck_changed
= !(surface
->flags
& SFLAG_GLCKEY
) != !(surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
);
2670 /* Reload if either the texture and sysmem have different ideas about the
2671 * color key, or the actual key values changed. */
2672 if (ck_changed
|| ((surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
)
2673 && (surface
->glCKey
.dwColorSpaceLowValue
!= surface
->SrcBltCKey
.dwColorSpaceLowValue
2674 || surface
->glCKey
.dwColorSpaceHighValue
!= surface
->SrcBltCKey
.dwColorSpaceHighValue
)))
2676 TRACE("Reloading because of color keying\n");
2677 /* To perform the color key conversion we need a sysmem copy of
2678 * the surface. Make sure we have it. */
2680 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
2681 /* Make sure the texture is reloaded because of the color key change,
2682 * this kills performance though :( */
2683 /* TODO: This is not necessarily needed with hw palettized texture support. */
2684 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
2685 /* Switching color keying on / off may change the internal format. */
2687 surface_force_reload(surface
);
2689 else if (!(surface
->flags
& flag
))
2691 TRACE("Reloading because surface is dirty.\n");
2695 TRACE("surface is already in texture\n");
2699 /* No partial locking for textures yet. */
2700 surface_load_location(surface
, flag
, NULL
);
2701 surface_evict_sysmem(surface
);
2706 /* See also float_16_to_32() in wined3d_private.h */
2707 static inline unsigned short float_32_to_16(const float *in
)
2710 float tmp
= fabsf(*in
);
2711 unsigned int mantissa
;
2714 /* Deal with special numbers */
2720 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
2722 if (tmp
< powf(2, 10))
2728 } while (tmp
< powf(2, 10));
2730 else if (tmp
>= powf(2, 11))
2736 } while (tmp
>= powf(2, 11));
2739 mantissa
= (unsigned int)tmp
;
2740 if (tmp
- mantissa
>= 0.5f
)
2741 ++mantissa
; /* Round to nearest, away from zero. */
2743 exp
+= 10; /* Normalize the mantissa. */
2744 exp
+= 15; /* Exponent is encoded with excess 15. */
2746 if (exp
> 30) /* too big */
2748 ret
= 0x7c00; /* INF */
2752 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2755 mantissa
= mantissa
>> 1;
2758 ret
= mantissa
& 0x3ff;
2762 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
2765 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
2769 ULONG CDECL
wined3d_surface_incref(struct wined3d_surface
*surface
)
2773 TRACE("Surface %p, container %p of type %#x.\n",
2774 surface
, surface
->container
.u
.base
, surface
->container
.type
);
2776 switch (surface
->container
.type
)
2778 case WINED3D_CONTAINER_TEXTURE
:
2779 return wined3d_texture_incref(surface
->container
.u
.texture
);
2781 case WINED3D_CONTAINER_SWAPCHAIN
:
2782 return wined3d_swapchain_incref(surface
->container
.u
.swapchain
);
2785 ERR("Unhandled container type %#x.\n", surface
->container
.type
);
2786 case WINED3D_CONTAINER_NONE
:
2790 refcount
= InterlockedIncrement(&surface
->resource
.ref
);
2791 TRACE("%p increasing refcount to %u.\n", surface
, refcount
);
2796 /* Do not call while under the GL lock. */
2797 ULONG CDECL
wined3d_surface_decref(struct wined3d_surface
*surface
)
2801 TRACE("Surface %p, container %p of type %#x.\n",
2802 surface
, surface
->container
.u
.base
, surface
->container
.type
);
2804 switch (surface
->container
.type
)
2806 case WINED3D_CONTAINER_TEXTURE
:
2807 return wined3d_texture_decref(surface
->container
.u
.texture
);
2809 case WINED3D_CONTAINER_SWAPCHAIN
:
2810 return wined3d_swapchain_decref(surface
->container
.u
.swapchain
);
2813 ERR("Unhandled container type %#x.\n", surface
->container
.type
);
2814 case WINED3D_CONTAINER_NONE
:
2818 refcount
= InterlockedDecrement(&surface
->resource
.ref
);
2819 TRACE("%p decreasing refcount to %u.\n", surface
, refcount
);
2823 surface
->surface_ops
->surface_cleanup(surface
);
2824 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
2826 TRACE("Destroyed surface %p.\n", surface
);
2827 HeapFree(GetProcessHeap(), 0, surface
);
2833 DWORD CDECL
wined3d_surface_set_priority(struct wined3d_surface
*surface
, DWORD priority
)
2835 return resource_set_priority(&surface
->resource
, priority
);
2838 DWORD CDECL
wined3d_surface_get_priority(const struct wined3d_surface
*surface
)
2840 return resource_get_priority(&surface
->resource
);
2843 void CDECL
wined3d_surface_preload(struct wined3d_surface
*surface
)
2845 TRACE("surface %p.\n", surface
);
2847 surface
->surface_ops
->surface_preload(surface
);
2850 void * CDECL
wined3d_surface_get_parent(const struct wined3d_surface
*surface
)
2852 TRACE("surface %p.\n", surface
);
2854 return surface
->resource
.parent
;
2857 struct wined3d_resource
* CDECL
wined3d_surface_get_resource(struct wined3d_surface
*surface
)
2859 TRACE("surface %p.\n", surface
);
2861 return &surface
->resource
;
2864 HRESULT CDECL
wined3d_surface_get_blt_status(const struct wined3d_surface
*surface
, DWORD flags
)
2866 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2870 case WINEDDGBS_CANBLT
:
2871 case WINEDDGBS_ISBLTDONE
:
2875 return WINED3DERR_INVALIDCALL
;
2879 HRESULT CDECL
wined3d_surface_get_flip_status(const struct wined3d_surface
*surface
, DWORD flags
)
2881 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2883 /* XXX: DDERR_INVALIDSURFACETYPE */
2887 case WINEDDGFS_CANFLIP
:
2888 case WINEDDGFS_ISFLIPDONE
:
2892 return WINED3DERR_INVALIDCALL
;
2896 HRESULT CDECL
wined3d_surface_is_lost(const struct wined3d_surface
*surface
)
2898 TRACE("surface %p.\n", surface
);
2900 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2901 return surface
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
2904 HRESULT CDECL
wined3d_surface_restore(struct wined3d_surface
*surface
)
2906 TRACE("surface %p.\n", surface
);
2908 /* So far we don't lose anything :) */
2909 surface
->flags
&= ~SFLAG_LOST
;
2913 HRESULT CDECL
wined3d_surface_set_palette(struct wined3d_surface
*surface
, struct wined3d_palette
*palette
)
2915 TRACE("surface %p, palette %p.\n", surface
, palette
);
2917 if (surface
->palette
== palette
)
2919 TRACE("Nop palette change.\n");
2923 if (surface
->palette
&& (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
))
2924 surface
->palette
->flags
&= ~WINEDDPCAPS_PRIMARYSURFACE
;
2926 surface
->palette
= palette
;
2930 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
2931 palette
->flags
|= WINEDDPCAPS_PRIMARYSURFACE
;
2933 surface
->surface_ops
->surface_realize_palette(surface
);
2939 HRESULT CDECL
wined3d_surface_set_color_key(struct wined3d_surface
*surface
,
2940 DWORD flags
, const WINEDDCOLORKEY
*color_key
)
2942 TRACE("surface %p, flags %#x, color_key %p.\n", surface
, flags
, color_key
);
2944 if (flags
& WINEDDCKEY_COLORSPACE
)
2946 FIXME(" colorkey value not supported (%08x) !\n", flags
);
2947 return WINED3DERR_INVALIDCALL
;
2950 /* Dirtify the surface, but only if a key was changed. */
2953 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
2955 case WINEDDCKEY_DESTBLT
:
2956 surface
->DestBltCKey
= *color_key
;
2957 surface
->CKeyFlags
|= WINEDDSD_CKDESTBLT
;
2960 case WINEDDCKEY_DESTOVERLAY
:
2961 surface
->DestOverlayCKey
= *color_key
;
2962 surface
->CKeyFlags
|= WINEDDSD_CKDESTOVERLAY
;
2965 case WINEDDCKEY_SRCOVERLAY
:
2966 surface
->SrcOverlayCKey
= *color_key
;
2967 surface
->CKeyFlags
|= WINEDDSD_CKSRCOVERLAY
;
2970 case WINEDDCKEY_SRCBLT
:
2971 surface
->SrcBltCKey
= *color_key
;
2972 surface
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
2978 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
2980 case WINEDDCKEY_DESTBLT
:
2981 surface
->CKeyFlags
&= ~WINEDDSD_CKDESTBLT
;
2984 case WINEDDCKEY_DESTOVERLAY
:
2985 surface
->CKeyFlags
&= ~WINEDDSD_CKDESTOVERLAY
;
2988 case WINEDDCKEY_SRCOVERLAY
:
2989 surface
->CKeyFlags
&= ~WINEDDSD_CKSRCOVERLAY
;
2992 case WINEDDCKEY_SRCBLT
:
2993 surface
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
3001 struct wined3d_palette
* CDECL
wined3d_surface_get_palette(const struct wined3d_surface
*surface
)
3003 TRACE("surface %p.\n", surface
);
3005 return surface
->palette
;
3008 DWORD CDECL
wined3d_surface_get_pitch(const struct wined3d_surface
*surface
)
3010 const struct wined3d_format
*format
= surface
->resource
.format
;
3013 TRACE("surface %p.\n", surface
);
3015 if ((format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_COMPRESSED
)
3017 /* Since compressed formats are block based, pitch means the amount of
3018 * bytes to the next row of block rather than the next row of pixels. */
3019 UINT row_block_count
= (surface
->resource
.width
+ format
->block_width
- 1) / format
->block_width
;
3020 pitch
= row_block_count
* format
->block_byte_count
;
3024 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
3025 pitch
= surface
->resource
.format
->byte_count
* surface
->resource
.width
; /* Bytes / row */
3026 pitch
= (pitch
+ alignment
- 1) & ~(alignment
- 1);
3029 TRACE("Returning %u.\n", pitch
);
3034 HRESULT CDECL
wined3d_surface_set_mem(struct wined3d_surface
*surface
, void *mem
)
3036 TRACE("surface %p, mem %p.\n", surface
, mem
);
3038 if (surface
->flags
& (SFLAG_LOCKED
| SFLAG_DCINUSE
))
3040 WARN("Surface is locked or the DC is in use.\n");
3041 return WINED3DERR_INVALIDCALL
;
3044 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3045 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
3047 ERR("Not supported on render targets.\n");
3048 return WINED3DERR_INVALIDCALL
;
3051 if (mem
&& mem
!= surface
->resource
.allocatedMemory
)
3053 void *release
= NULL
;
3055 /* Do I have to copy the old surface content? */
3056 if (surface
->flags
& SFLAG_DIBSECTION
)
3058 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
3059 DeleteDC(surface
->hDC
);
3060 /* Release the DIB section. */
3061 DeleteObject(surface
->dib
.DIBsection
);
3062 surface
->dib
.bitmap_data
= NULL
;
3063 surface
->resource
.allocatedMemory
= NULL
;
3064 surface
->hDC
= NULL
;
3065 surface
->flags
&= ~SFLAG_DIBSECTION
;
3067 else if (!(surface
->flags
& SFLAG_USERPTR
))
3069 release
= surface
->resource
.heapMemory
;
3070 surface
->resource
.heapMemory
= NULL
;
3072 surface
->resource
.allocatedMemory
= mem
;
3073 surface
->flags
|= SFLAG_USERPTR
;
3075 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3076 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
3078 /* For client textures OpenGL has to be notified. */
3079 if (surface
->flags
& SFLAG_CLIENT
)
3080 surface_release_client_storage(surface
);
3082 /* Now free the old memory if any. */
3083 HeapFree(GetProcessHeap(), 0, release
);
3085 else if (surface
->flags
& SFLAG_USERPTR
)
3087 /* HeapMemory should be NULL already. */
3088 if (surface
->resource
.heapMemory
)
3089 ERR("User pointer surface has heap memory allocated.\n");
3093 surface
->resource
.allocatedMemory
= NULL
;
3094 surface
->flags
&= ~(SFLAG_USERPTR
| SFLAG_INSYSMEM
);
3096 if (surface
->flags
& SFLAG_CLIENT
)
3097 surface_release_client_storage(surface
);
3099 surface_prepare_system_memory(surface
);
3102 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
3108 HRESULT CDECL
wined3d_surface_set_overlay_position(struct wined3d_surface
*surface
, LONG x
, LONG y
)
3112 TRACE("surface %p, x %d, y %d.\n", surface
, x
, y
);
3114 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3116 WARN("Not an overlay surface.\n");
3117 return WINEDDERR_NOTAOVERLAYSURFACE
;
3120 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
3121 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
3122 surface
->overlay_destrect
.left
= x
;
3123 surface
->overlay_destrect
.top
= y
;
3124 surface
->overlay_destrect
.right
= x
+ w
;
3125 surface
->overlay_destrect
.bottom
= y
+ h
;
3127 surface
->surface_ops
->surface_draw_overlay(surface
);
3132 HRESULT CDECL
wined3d_surface_get_overlay_position(const struct wined3d_surface
*surface
, LONG
*x
, LONG
*y
)
3134 TRACE("surface %p, x %p, y %p.\n", surface
, x
, y
);
3136 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3138 TRACE("Not an overlay surface.\n");
3139 return WINEDDERR_NOTAOVERLAYSURFACE
;
3142 if (!surface
->overlay_dest
)
3144 TRACE("Overlay not visible.\n");
3147 return WINEDDERR_OVERLAYNOTVISIBLE
;
3150 *x
= surface
->overlay_destrect
.left
;
3151 *y
= surface
->overlay_destrect
.top
;
3153 TRACE("Returning position %d, %d.\n", *x
, *y
);
3158 HRESULT CDECL
wined3d_surface_update_overlay_z_order(struct wined3d_surface
*surface
,
3159 DWORD flags
, struct wined3d_surface
*ref
)
3161 FIXME("surface %p, flags %#x, ref %p stub!\n", surface
, flags
, ref
);
3163 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3165 TRACE("Not an overlay surface.\n");
3166 return WINEDDERR_NOTAOVERLAYSURFACE
;
3172 HRESULT CDECL
wined3d_surface_update_overlay(struct wined3d_surface
*surface
, const RECT
*src_rect
,
3173 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
, DWORD flags
, const WINEDDOVERLAYFX
*fx
)
3175 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3176 surface
, wine_dbgstr_rect(src_rect
), dst_surface
, wine_dbgstr_rect(dst_rect
), flags
, fx
);
3178 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3180 WARN("Not an overlay surface.\n");
3181 return WINEDDERR_NOTAOVERLAYSURFACE
;
3183 else if (!dst_surface
)
3185 WARN("Dest surface is NULL.\n");
3186 return WINED3DERR_INVALIDCALL
;
3191 surface
->overlay_srcrect
= *src_rect
;
3195 surface
->overlay_srcrect
.left
= 0;
3196 surface
->overlay_srcrect
.top
= 0;
3197 surface
->overlay_srcrect
.right
= surface
->resource
.width
;
3198 surface
->overlay_srcrect
.bottom
= surface
->resource
.height
;
3203 surface
->overlay_destrect
= *dst_rect
;
3207 surface
->overlay_destrect
.left
= 0;
3208 surface
->overlay_destrect
.top
= 0;
3209 surface
->overlay_destrect
.right
= dst_surface
? dst_surface
->resource
.width
: 0;
3210 surface
->overlay_destrect
.bottom
= dst_surface
? dst_surface
->resource
.height
: 0;
3213 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
3215 list_remove(&surface
->overlay_entry
);
3218 if (flags
& WINEDDOVER_SHOW
)
3220 if (surface
->overlay_dest
!= dst_surface
)
3222 surface
->overlay_dest
= dst_surface
;
3223 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
3226 else if (flags
& WINEDDOVER_HIDE
)
3228 /* tests show that the rectangles are erased on hide */
3229 surface
->overlay_srcrect
.left
= 0; surface
->overlay_srcrect
.top
= 0;
3230 surface
->overlay_srcrect
.right
= 0; surface
->overlay_srcrect
.bottom
= 0;
3231 surface
->overlay_destrect
.left
= 0; surface
->overlay_destrect
.top
= 0;
3232 surface
->overlay_destrect
.right
= 0; surface
->overlay_destrect
.bottom
= 0;
3233 surface
->overlay_dest
= NULL
;
3236 surface
->surface_ops
->surface_draw_overlay(surface
);
3241 HRESULT CDECL
wined3d_surface_set_clipper(struct wined3d_surface
*surface
, struct wined3d_clipper
*clipper
)
3243 TRACE("surface %p, clipper %p.\n", surface
, clipper
);
3245 surface
->clipper
= clipper
;
3250 struct wined3d_clipper
* CDECL
wined3d_surface_get_clipper(const struct wined3d_surface
*surface
)
3252 TRACE("surface %p.\n", surface
);
3254 return surface
->clipper
;
3257 HRESULT CDECL
wined3d_surface_set_format(struct wined3d_surface
*surface
, enum wined3d_format_id format_id
)
3259 const struct wined3d_format
*format
= wined3d_get_format(&surface
->resource
.device
->adapter
->gl_info
, format_id
);
3261 TRACE("surface %p, format %s.\n", surface
, debug_d3dformat(format_id
));
3263 if (surface
->resource
.format
->id
!= WINED3DFMT_UNKNOWN
)
3265 FIXME("The format of the surface must be WINED3DFORMAT_UNKNOWN.\n");
3266 return WINED3DERR_INVALIDCALL
;
3269 surface
->resource
.size
= wined3d_format_calculate_size(format
, surface
->resource
.device
->surface_alignment
,
3270 surface
->pow2Width
, surface
->pow2Height
);
3271 surface
->flags
|= (WINED3DFMT_D16_LOCKABLE
== format_id
) ? SFLAG_LOCKABLE
: 0;
3272 surface
->resource
.format
= format
;
3274 TRACE("size %u, byte_count %u\n", surface
->resource
.size
, format
->byte_count
);
3275 TRACE("glFormat %#x, glInternal %#x, glType %#x.\n",
3276 format
->glFormat
, format
->glInternal
, format
->glType
);
3281 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
3282 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3284 unsigned short *dst_s
;
3288 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3290 for (y
= 0; y
< h
; ++y
)
3292 src_f
= (const float *)(src
+ y
* pitch_in
);
3293 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
3294 for (x
= 0; x
< w
; ++x
)
3296 dst_s
[x
] = float_32_to_16(src_f
+ x
);
3301 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3302 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3304 static const unsigned char convert_5to8
[] =
3306 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3307 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3308 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3309 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3311 static const unsigned char convert_6to8
[] =
3313 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3314 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3315 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3316 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3317 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3318 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3319 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3320 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3324 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3326 for (y
= 0; y
< h
; ++y
)
3328 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
3329 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3330 for (x
= 0; x
< w
; ++x
)
3332 WORD pixel
= src_line
[x
];
3333 dst_line
[x
] = 0xff000000
3334 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
3335 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
3336 | convert_5to8
[(pixel
& 0x001f)];
3341 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3342 * in both cases we're just setting the X / Alpha channel to 0xff. */
3343 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3344 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3348 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3350 for (y
= 0; y
< h
; ++y
)
3352 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
3353 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3355 for (x
= 0; x
< w
; ++x
)
3357 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
3362 static inline BYTE
cliptobyte(int x
)
3364 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
3367 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3368 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3370 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
3373 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3375 for (y
= 0; y
< h
; ++y
)
3377 const BYTE
*src_line
= src
+ y
* pitch_in
;
3378 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3379 for (x
= 0; x
< w
; ++x
)
3381 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3382 * C = Y - 16; D = U - 128; E = V - 128;
3383 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3384 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3385 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3386 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3387 * U and V are shared between the pixels. */
3388 if (!(x
& 1)) /* For every even pixel, read new U and V. */
3390 d
= (int) src_line
[1] - 128;
3391 e
= (int) src_line
[3] - 128;
3393 g2
= - 100 * d
- 208 * e
+ 128;
3396 c2
= 298 * ((int) src_line
[0] - 16);
3397 dst_line
[x
] = 0xff000000
3398 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
3399 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
3400 | cliptobyte((c2
+ b2
) >> 8); /* blue */
3401 /* Scale RGB values to 0..255 range,
3402 * then clip them if still not in range (may be negative),
3403 * then shift them within DWORD if necessary. */
3409 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
3410 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3413 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
3415 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
3417 for (y
= 0; y
< h
; ++y
)
3419 const BYTE
*src_line
= src
+ y
* pitch_in
;
3420 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
3421 for (x
= 0; x
< w
; ++x
)
3423 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3424 * C = Y - 16; D = U - 128; E = V - 128;
3425 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3426 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3427 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3428 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3429 * U and V are shared between the pixels. */
3430 if (!(x
& 1)) /* For every even pixel, read new U and V. */
3432 d
= (int) src_line
[1] - 128;
3433 e
= (int) src_line
[3] - 128;
3435 g2
= - 100 * d
- 208 * e
+ 128;
3438 c2
= 298 * ((int) src_line
[0] - 16);
3439 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
3440 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
3441 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
3442 /* Scale RGB values to 0..255 range,
3443 * then clip them if still not in range (may be negative),
3444 * then shift them within DWORD if necessary. */
3450 struct d3dfmt_convertor_desc
3452 enum wined3d_format_id from
, to
;
3453 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
3456 static const struct d3dfmt_convertor_desc convertors
[] =
3458 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
3459 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
3460 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
3461 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
3462 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
3463 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
3466 static inline const struct d3dfmt_convertor_desc
*find_convertor(enum wined3d_format_id from
,
3467 enum wined3d_format_id to
)
3471 for (i
= 0; i
< (sizeof(convertors
) / sizeof(*convertors
)); ++i
)
3473 if (convertors
[i
].from
== from
&& convertors
[i
].to
== to
)
3474 return &convertors
[i
];
3480 /*****************************************************************************
3481 * surface_convert_format
3483 * Creates a duplicate of a surface in a different format. Is used by Blt to
3484 * blit between surfaces with different formats.
3487 * source: Source surface
3488 * fmt: Requested destination format
3490 *****************************************************************************/
3491 static struct wined3d_surface
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
3493 const struct d3dfmt_convertor_desc
*conv
;
3494 WINED3DLOCKED_RECT lock_src
, lock_dst
;
3495 struct wined3d_surface
*ret
= NULL
;
3498 conv
= find_convertor(source
->resource
.format
->id
, to_fmt
);
3501 FIXME("Cannot find a conversion function from format %s to %s.\n",
3502 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
3506 wined3d_surface_create(source
->resource
.device
, source
->resource
.width
,
3507 source
->resource
.height
, to_fmt
, TRUE
/* lockable */, TRUE
/* discard */, 0 /* level */,
3508 0 /* usage */, WINED3DPOOL_SCRATCH
, WINED3DMULTISAMPLE_NONE
/* TODO: Multisampled conversion */,
3509 0 /* MultiSampleQuality */, source
->surface_type
, NULL
/* parent */, &wined3d_null_parent_ops
, &ret
);
3512 ERR("Failed to create a destination surface for conversion.\n");
3516 memset(&lock_src
, 0, sizeof(lock_src
));
3517 memset(&lock_dst
, 0, sizeof(lock_dst
));
3519 hr
= wined3d_surface_map(source
, &lock_src
, NULL
, WINED3DLOCK_READONLY
);
3522 ERR("Failed to lock the source surface.\n");
3523 wined3d_surface_decref(ret
);
3526 hr
= wined3d_surface_map(ret
, &lock_dst
, NULL
, WINED3DLOCK_READONLY
);
3529 ERR("Failed to lock the destination surface.\n");
3530 wined3d_surface_unmap(source
);
3531 wined3d_surface_decref(ret
);
3535 conv
->convert(lock_src
.pBits
, lock_dst
.pBits
, lock_src
.Pitch
, lock_dst
.Pitch
,
3536 source
->resource
.width
, source
->resource
.height
);
3538 wined3d_surface_unmap(ret
);
3539 wined3d_surface_unmap(source
);
3544 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
3545 unsigned int bpp
, UINT pitch
, DWORD color
)
3552 #define COLORFILL_ROW(type) \
3554 type *d = (type *)buf; \
3555 for (x = 0; x < width; ++x) \
3556 d[x] = (type)color; \
3562 COLORFILL_ROW(BYTE
);
3566 COLORFILL_ROW(WORD
);
3572 for (x
= 0; x
< width
; ++x
, d
+= 3)
3574 d
[0] = (color
) & 0xFF;
3575 d
[1] = (color
>> 8) & 0xFF;
3576 d
[2] = (color
>> 16) & 0xFF;
3581 COLORFILL_ROW(DWORD
);
3585 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
3586 return WINED3DERR_NOTAVAILABLE
;
3589 #undef COLORFILL_ROW
3591 /* Now copy first row. */
3593 for (y
= 1; y
< height
; ++y
)
3596 memcpy(buf
, first
, width
* bpp
);
3602 HRESULT CDECL
wined3d_surface_unmap(struct wined3d_surface
*surface
)
3604 TRACE("surface %p.\n", surface
);
3606 if (!(surface
->flags
& SFLAG_LOCKED
))
3608 WARN("Trying to unmap unmapped surface.\n");
3609 return WINEDDERR_NOTLOCKED
;
3611 surface
->flags
&= ~SFLAG_LOCKED
;
3613 surface
->surface_ops
->surface_unmap(surface
);
3618 HRESULT CDECL
wined3d_surface_map(struct wined3d_surface
*surface
,
3619 WINED3DLOCKED_RECT
*locked_rect
, const RECT
*rect
, DWORD flags
)
3621 TRACE("surface %p, locked_rect %p, rect %s, flags %#x.\n",
3622 surface
, locked_rect
, wine_dbgstr_rect(rect
), flags
);
3624 if (surface
->flags
& SFLAG_LOCKED
)
3626 WARN("Surface is already mapped.\n");
3627 return WINED3DERR_INVALIDCALL
;
3629 surface
->flags
|= SFLAG_LOCKED
;
3631 if (!(surface
->flags
& SFLAG_LOCKABLE
))
3632 WARN("Trying to lock unlockable surface.\n");
3634 surface
->surface_ops
->surface_map(surface
, rect
, flags
);
3636 locked_rect
->Pitch
= wined3d_surface_get_pitch(surface
);
3640 locked_rect
->pBits
= surface
->resource
.allocatedMemory
;
3641 surface
->lockedRect
.left
= 0;
3642 surface
->lockedRect
.top
= 0;
3643 surface
->lockedRect
.right
= surface
->resource
.width
;
3644 surface
->lockedRect
.bottom
= surface
->resource
.height
;
3648 const struct wined3d_format
*format
= surface
->resource
.format
;
3650 if ((format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_COMPRESSED
)
3652 /* Compressed textures are block based, so calculate the offset of
3653 * the block that contains the top-left pixel of the locked rectangle. */
3654 locked_rect
->pBits
= surface
->resource
.allocatedMemory
3655 + ((rect
->top
/ format
->block_height
) * locked_rect
->Pitch
)
3656 + ((rect
->left
/ format
->block_width
) * format
->block_byte_count
);
3660 locked_rect
->pBits
= surface
->resource
.allocatedMemory
3661 + (locked_rect
->Pitch
* rect
->top
)
3662 + (rect
->left
* format
->byte_count
);
3664 surface
->lockedRect
.left
= rect
->left
;
3665 surface
->lockedRect
.top
= rect
->top
;
3666 surface
->lockedRect
.right
= rect
->right
;
3667 surface
->lockedRect
.bottom
= rect
->bottom
;
3670 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
3671 TRACE("Returning memory %p, pitch %u.\n", locked_rect
->pBits
, locked_rect
->Pitch
);
3676 HRESULT CDECL
wined3d_surface_getdc(struct wined3d_surface
*surface
, HDC
*dc
)
3680 TRACE("surface %p, dc %p.\n", surface
, dc
);
3682 if (surface
->flags
& SFLAG_USERPTR
)
3684 ERR("Not supported on surfaces with application-provided memory.\n");
3685 return WINEDDERR_NODC
;
3688 /* Give more detailed info for ddraw. */
3689 if (surface
->flags
& SFLAG_DCINUSE
)
3690 return WINEDDERR_DCALREADYCREATED
;
3692 /* Can't GetDC if the surface is locked. */
3693 if (surface
->flags
& SFLAG_LOCKED
)
3694 return WINED3DERR_INVALIDCALL
;
3696 hr
= surface
->surface_ops
->surface_getdc(surface
);
3700 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3701 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
3703 /* GetDC on palettized formats is unsupported in D3D9, and the method
3704 * is missing in D3D8, so this should only be used for DX <=7
3705 * surfaces (with non-device palettes). */
3706 const PALETTEENTRY
*pal
= NULL
;
3708 if (surface
->palette
)
3710 pal
= surface
->palette
->palents
;
3714 struct wined3d_swapchain
*swapchain
= surface
->resource
.device
->swapchains
[0];
3715 struct wined3d_surface
*dds_primary
= swapchain
->front_buffer
;
3717 if (dds_primary
&& dds_primary
->palette
)
3718 pal
= dds_primary
->palette
->palents
;
3726 for (i
= 0; i
< 256; ++i
)
3728 col
[i
].rgbRed
= pal
[i
].peRed
;
3729 col
[i
].rgbGreen
= pal
[i
].peGreen
;
3730 col
[i
].rgbBlue
= pal
[i
].peBlue
;
3731 col
[i
].rgbReserved
= 0;
3733 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
3737 surface
->flags
|= SFLAG_DCINUSE
;
3740 TRACE("Returning dc %p.\n", *dc
);
3745 HRESULT CDECL
wined3d_surface_releasedc(struct wined3d_surface
*surface
, HDC dc
)
3747 TRACE("surface %p, dc %p.\n", surface
, dc
);
3749 if (!(surface
->flags
& SFLAG_DCINUSE
))
3750 return WINEDDERR_NODC
;
3752 if (surface
->hDC
!= dc
)
3754 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
3756 return WINEDDERR_NODC
;
3759 /* Copy the contents of the DIB over to the PBO. */
3760 if ((surface
->flags
& SFLAG_PBO
) && surface
->resource
.allocatedMemory
)
3761 memcpy(surface
->resource
.allocatedMemory
, surface
->dib
.bitmap_data
, surface
->resource
.size
);
3763 /* We locked first, so unlock now. */
3764 wined3d_surface_unmap(surface
);
3766 surface
->flags
&= ~SFLAG_DCINUSE
;
3771 HRESULT CDECL
wined3d_surface_flip(struct wined3d_surface
*surface
, struct wined3d_surface
*override
, DWORD flags
)
3773 TRACE("surface %p, override %p, flags %#x.\n", surface
, override
, flags
);
3779 FIXME("Ignoring flags %#x.\n", flags
);
3781 WARN("Ignoring flags %#x.\n", flags
);
3784 /* FIXME: This will also prevent overlay flips, since overlays aren't on
3785 * a swapchain either. */
3786 if (surface
->container
.type
!= WINED3D_CONTAINER_SWAPCHAIN
)
3788 ERR("Flipped surface is not on a swapchain.\n");
3789 return WINEDDERR_NOTFLIPPABLE
;
3792 /* Flipping is only supported on render targets and overlays. */
3793 if (!(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_OVERLAY
)))
3795 WARN("Tried to flip a non-render target, non-overlay surface.\n");
3796 return WINEDDERR_NOTFLIPPABLE
;
3799 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
3801 flip_surface(surface
, override
);
3803 /* Update the overlay if it is visible */
3804 if (surface
->overlay_dest
)
3805 return surface
->surface_ops
->surface_draw_overlay(surface
);
3810 return wined3d_surface_blt(surface
, NULL
, override
, NULL
, 0, NULL
, WINED3DTEXF_POINT
);
3813 /* Do not call while under the GL lock. */
3814 void surface_internal_preload(struct wined3d_surface
*surface
, enum WINED3DSRGB srgb
)
3816 struct wined3d_device
*device
= surface
->resource
.device
;
3818 TRACE("iface %p, srgb %#x.\n", surface
, srgb
);
3820 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
3822 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
3824 TRACE("Passing to container (%p).\n", texture
);
3825 texture
->texture_ops
->texture_preload(texture
, srgb
);
3829 struct wined3d_context
*context
;
3831 TRACE("(%p) : About to load surface\n", surface
);
3833 /* TODO: Use already acquired context when possible. */
3834 context
= context_acquire(device
, NULL
);
3836 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3837 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
3839 if (palette9_changed(surface
))
3841 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
3842 /* TODO: This is not necessarily needed with hw palettized texture support */
3843 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
3844 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
3845 surface_modify_location(surface
, SFLAG_INTEXTURE
, FALSE
);
3849 surface_load(surface
, srgb
== SRGB_SRGB
? TRUE
: FALSE
);
3851 if (surface
->resource
.pool
== WINED3DPOOL_DEFAULT
)
3853 /* Tell opengl to try and keep this texture in video ram (well mostly) */
3857 glPrioritizeTextures(1, &surface
->texture_name
, &tmp
);
3861 context_release(context
);
3865 BOOL
surface_init_sysmem(struct wined3d_surface
*surface
)
3867 if (!surface
->resource
.allocatedMemory
)
3869 surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
3870 surface
->resource
.size
+ RESOURCE_ALIGNMENT
);
3871 if (!surface
->resource
.heapMemory
)
3873 ERR("Out of memory\n");
3876 surface
->resource
.allocatedMemory
=
3877 (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
+ (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
3881 memset(surface
->resource
.allocatedMemory
, 0, surface
->resource
.size
);
3884 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
3889 /* Read the framebuffer back into the surface */
3890 static void read_from_framebuffer(struct wined3d_surface
*surface
, const RECT
*rect
, void *dest
, UINT pitch
)
3892 struct wined3d_device
*device
= surface
->resource
.device
;
3893 const struct wined3d_gl_info
*gl_info
;
3894 struct wined3d_context
*context
;
3898 BYTE
*row
, *top
, *bottom
;
3902 BOOL srcIsUpsideDown
;
3907 if(wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
) {
3908 static BOOL warned
= FALSE
;
3910 ERR("The application tries to lock the render target, but render target locking is disabled\n");
3916 context
= context_acquire(device
, surface
);
3917 context_apply_blit_state(context
, device
);
3918 gl_info
= context
->gl_info
;
3922 /* Select the correct read buffer, and give some debug output.
3923 * There is no need to keep track of the current read buffer or reset it, every part of the code
3924 * that reads sets the read buffer as desired.
3926 if (surface_is_offscreen(surface
))
3928 /* Mapping the primary render target which is not on a swapchain.
3929 * Read from the back buffer. */
3930 TRACE("Mapping offscreen render target.\n");
3931 glReadBuffer(device
->offscreenBuffer
);
3932 srcIsUpsideDown
= TRUE
;
3936 /* Onscreen surfaces are always part of a swapchain */
3937 GLenum buffer
= surface_get_gl_buffer(surface
);
3938 TRACE("Mapping %#x buffer.\n", buffer
);
3939 glReadBuffer(buffer
);
3940 checkGLcall("glReadBuffer");
3941 srcIsUpsideDown
= FALSE
;
3944 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
3947 local_rect
.left
= 0;
3949 local_rect
.right
= surface
->resource
.width
;
3950 local_rect
.bottom
= surface
->resource
.height
;
3956 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
3958 switch (surface
->resource
.format
->id
)
3960 case WINED3DFMT_P8_UINT
:
3962 if (primary_render_target_is_p8(device
))
3964 /* In case of P8 render targets the index is stored in the alpha component */
3966 type
= GL_UNSIGNED_BYTE
;
3968 bpp
= surface
->resource
.format
->byte_count
;
3972 /* GL can't return palettized data, so read ARGB pixels into a
3973 * separate block of memory and convert them into palettized format
3974 * in software. Slow, but if the app means to use palettized render
3975 * targets and locks it...
3977 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
3978 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
3979 * for the color channels when palettizing the colors.
3982 type
= GL_UNSIGNED_BYTE
;
3984 mem
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
* 3);
3987 ERR("Out of memory\n");
3991 bpp
= surface
->resource
.format
->byte_count
* 3;
3998 fmt
= surface
->resource
.format
->glFormat
;
3999 type
= surface
->resource
.format
->glType
;
4000 bpp
= surface
->resource
.format
->byte_count
;
4003 if (surface
->flags
& SFLAG_PBO
)
4005 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
4006 checkGLcall("glBindBufferARB");
4009 ERR("mem not null for pbo -- unexpected\n");
4014 /* Save old pixel store pack state */
4015 glGetIntegerv(GL_PACK_ROW_LENGTH
, &rowLen
);
4016 checkGLcall("glGetIntegerv");
4017 glGetIntegerv(GL_PACK_SKIP_PIXELS
, &skipPix
);
4018 checkGLcall("glGetIntegerv");
4019 glGetIntegerv(GL_PACK_SKIP_ROWS
, &skipRow
);
4020 checkGLcall("glGetIntegerv");
4022 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4023 glPixelStorei(GL_PACK_ROW_LENGTH
, surface
->resource
.width
);
4024 checkGLcall("glPixelStorei");
4025 glPixelStorei(GL_PACK_SKIP_PIXELS
, local_rect
.left
);
4026 checkGLcall("glPixelStorei");
4027 glPixelStorei(GL_PACK_SKIP_ROWS
, local_rect
.top
);
4028 checkGLcall("glPixelStorei");
4030 glReadPixels(local_rect
.left
, !srcIsUpsideDown
? (surface
->resource
.height
- local_rect
.bottom
) : local_rect
.top
,
4031 local_rect
.right
- local_rect
.left
,
4032 local_rect
.bottom
- local_rect
.top
,
4034 checkGLcall("glReadPixels");
4036 /* Reset previous pixel store pack state */
4037 glPixelStorei(GL_PACK_ROW_LENGTH
, rowLen
);
4038 checkGLcall("glPixelStorei");
4039 glPixelStorei(GL_PACK_SKIP_PIXELS
, skipPix
);
4040 checkGLcall("glPixelStorei");
4041 glPixelStorei(GL_PACK_SKIP_ROWS
, skipRow
);
4042 checkGLcall("glPixelStorei");
4044 if (surface
->flags
& SFLAG_PBO
)
4046 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
4047 checkGLcall("glBindBufferARB");
4049 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4050 * to get a pointer to it and perform the flipping in software. This is a lot
4051 * faster than calling glReadPixels for each line. In case we want more speed
4052 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4053 if (!srcIsUpsideDown
)
4055 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
4056 checkGLcall("glBindBufferARB");
4058 mem
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
4059 checkGLcall("glMapBufferARB");
4063 /* TODO: Merge this with the palettization loop below for P8 targets */
4064 if(!srcIsUpsideDown
) {
4066 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4067 Flip the lines in software */
4068 len
= (local_rect
.right
- local_rect
.left
) * bpp
;
4069 off
= local_rect
.left
* bpp
;
4071 row
= HeapAlloc(GetProcessHeap(), 0, len
);
4073 ERR("Out of memory\n");
4074 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
4075 HeapFree(GetProcessHeap(), 0, mem
);
4080 top
= mem
+ pitch
* local_rect
.top
;
4081 bottom
= mem
+ pitch
* (local_rect
.bottom
- 1);
4082 for(i
= 0; i
< (local_rect
.bottom
- local_rect
.top
) / 2; i
++) {
4083 memcpy(row
, top
+ off
, len
);
4084 memcpy(top
+ off
, bottom
+ off
, len
);
4085 memcpy(bottom
+ off
, row
, len
);
4089 HeapFree(GetProcessHeap(), 0, row
);
4091 /* Unmap the temp PBO buffer */
4092 if (surface
->flags
& SFLAG_PBO
)
4094 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
4095 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4100 context_release(context
);
4102 /* For P8 textures we need to perform an inverse palette lookup. This is
4103 * done by searching for a palette index which matches the RGB value.
4104 * Note this isn't guaranteed to work when there are multiple entries for
4105 * the same color but we have no choice. In case of P8 render targets,
4106 * the index is stored in the alpha component so no conversion is needed. */
4107 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
&& !primary_render_target_is_p8(device
))
4109 const PALETTEENTRY
*pal
= NULL
;
4110 DWORD width
= pitch
/ 3;
4113 if (surface
->palette
)
4115 pal
= surface
->palette
->palents
;
4119 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4120 HeapFree(GetProcessHeap(), 0, mem
);
4124 for(y
= local_rect
.top
; y
< local_rect
.bottom
; y
++) {
4125 for(x
= local_rect
.left
; x
< local_rect
.right
; x
++) {
4126 /* start lines pixels */
4127 const BYTE
*blue
= mem
+ y
* pitch
+ x
* (sizeof(BYTE
) * 3);
4128 const BYTE
*green
= blue
+ 1;
4129 const BYTE
*red
= green
+ 1;
4131 for(c
= 0; c
< 256; c
++) {
4132 if(*red
== pal
[c
].peRed
&&
4133 *green
== pal
[c
].peGreen
&&
4134 *blue
== pal
[c
].peBlue
)
4136 *((BYTE
*) dest
+ y
* width
+ x
) = c
;
4142 HeapFree(GetProcessHeap(), 0, mem
);
4146 /* Read the framebuffer contents into a texture */
4147 static void read_from_framebuffer_texture(struct wined3d_surface
*surface
, BOOL srgb
)
4149 struct wined3d_device
*device
= surface
->resource
.device
;
4150 struct wined3d_context
*context
;
4152 if (!surface_is_offscreen(surface
))
4154 /* We would need to flip onscreen surfaces, but there's no efficient
4155 * way to do that here. It makes more sense for the caller to
4156 * explicitly go through sysmem. */
4157 ERR("Not supported for onscreen targets.\n");
4161 /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
4162 * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
4163 * states in the stateblock, and no driver was found yet that had bugs in that regard.
4165 context
= context_acquire(device
, surface
);
4166 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
4168 surface_prepare_texture(surface
, context
, srgb
);
4169 surface_bind_and_dirtify(surface
, context
, srgb
);
4171 TRACE("Reading back offscreen render target %p.\n", surface
);
4175 glReadBuffer(device
->offscreenBuffer
);
4176 checkGLcall("glReadBuffer");
4178 glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
4179 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
4180 checkGLcall("glCopyTexSubImage2D");
4184 context_release(context
);
4187 /* Context activation is done by the caller. */
4188 static void surface_prepare_texture_internal(struct wined3d_surface
*surface
,
4189 struct wined3d_context
*context
, BOOL srgb
)
4191 DWORD alloc_flag
= srgb
? SFLAG_SRGBALLOCATED
: SFLAG_ALLOCATED
;
4192 CONVERT_TYPES convert
;
4193 struct wined3d_format format
;
4195 if (surface
->flags
& alloc_flag
) return;
4197 d3dfmt_get_conv(surface
, TRUE
, TRUE
, &format
, &convert
);
4198 if (convert
!= NO_CONVERSION
|| format
.convert
) surface
->flags
|= SFLAG_CONVERTED
;
4199 else surface
->flags
&= ~SFLAG_CONVERTED
;
4201 surface_bind_and_dirtify(surface
, context
, srgb
);
4202 surface_allocate_surface(surface
, context
->gl_info
, &format
, srgb
);
4203 surface
->flags
|= alloc_flag
;
4206 /* Context activation is done by the caller. */
4207 void surface_prepare_texture(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
4209 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
4211 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
4212 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
4215 TRACE("surface %p is a subresource of texture %p.\n", surface
, texture
);
4217 for (i
= 0; i
< sub_count
; ++i
)
4219 struct wined3d_surface
*s
= surface_from_resource(texture
->sub_resources
[i
]);
4220 surface_prepare_texture_internal(s
, context
, srgb
);
4226 surface_prepare_texture_internal(surface
, context
, srgb
);
4229 void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
4233 if (surface
->rb_multisample
)
4236 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
4237 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
4238 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, surface
->resource
.multisample_type
,
4239 surface
->resource
.format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
4240 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
4244 if (surface
->rb_resolved
)
4247 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
4248 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
4249 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, surface
->resource
.format
->glInternal
,
4250 surface
->pow2Width
, surface
->pow2Height
);
4251 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
4255 static void flush_to_framebuffer_drawpixels(struct wined3d_surface
*surface
,
4256 const RECT
*rect
, GLenum fmt
, GLenum type
, UINT bpp
, const BYTE
*mem
)
4258 struct wined3d_device
*device
= surface
->resource
.device
;
4259 UINT pitch
= wined3d_surface_get_pitch(surface
);
4260 const struct wined3d_gl_info
*gl_info
;
4261 struct wined3d_context
*context
;
4265 surface_get_rect(surface
, rect
, &local_rect
);
4267 mem
+= local_rect
.top
* pitch
+ local_rect
.left
* bpp
;
4268 w
= local_rect
.right
- local_rect
.left
;
4269 h
= local_rect
.bottom
- local_rect
.top
;
4271 /* Activate the correct context for the render target */
4272 context
= context_acquire(device
, surface
);
4273 context_apply_blit_state(context
, device
);
4274 gl_info
= context
->gl_info
;
4278 if (!surface_is_offscreen(surface
))
4280 GLenum buffer
= surface_get_gl_buffer(surface
);
4281 TRACE("Unlocking %#x buffer.\n", buffer
);
4282 context_set_draw_buffer(context
, buffer
);
4284 surface_translate_drawable_coords(surface
, context
->win_handle
, &local_rect
);
4285 glPixelZoom(1.0f
, -1.0f
);
4289 /* Primary offscreen render target */
4290 TRACE("Offscreen render target.\n");
4291 context_set_draw_buffer(context
, device
->offscreenBuffer
);
4293 glPixelZoom(1.0f
, 1.0f
);
4296 glRasterPos3i(local_rect
.left
, local_rect
.top
, 1);
4297 checkGLcall("glRasterPos3i");
4299 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4300 glPixelStorei(GL_UNPACK_ROW_LENGTH
, surface
->resource
.width
);
4302 if (surface
->flags
& SFLAG_PBO
)
4304 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
4305 checkGLcall("glBindBufferARB");
4308 glDrawPixels(w
, h
, fmt
, type
, mem
);
4309 checkGLcall("glDrawPixels");
4311 if (surface
->flags
& SFLAG_PBO
)
4313 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4314 checkGLcall("glBindBufferARB");
4317 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
4318 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4322 if (wined3d_settings
.strict_draw_ordering
4323 || (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
4324 && surface
->container
.u
.swapchain
->front_buffer
== surface
))
4327 context_release(context
);
4330 HRESULT
d3dfmt_get_conv(const struct wined3d_surface
*surface
, BOOL need_alpha_ck
,
4331 BOOL use_texturing
, struct wined3d_format
*format
, CONVERT_TYPES
*convert
)
4333 BOOL colorkey_active
= need_alpha_ck
&& (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
);
4334 const struct wined3d_device
*device
= surface
->resource
.device
;
4335 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4336 BOOL blit_supported
= FALSE
;
4338 /* Copy the default values from the surface. Below we might perform fixups */
4339 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
4340 *format
= *surface
->resource
.format
;
4341 *convert
= NO_CONVERSION
;
4343 /* Ok, now look if we have to do any conversion */
4344 switch (surface
->resource
.format
->id
)
4346 case WINED3DFMT_P8_UINT
:
4347 /* Below the call to blit_supported is disabled for Wine 1.2
4348 * because the function isn't operating correctly yet. At the
4349 * moment 8-bit blits are handled in software and if certain GL
4350 * extensions are around, surface conversion is performed at
4351 * upload time. The blit_supported call recognizes it as a
4352 * destination fixup. This type of upload 'fixup' and 8-bit to
4353 * 8-bit blits need to be handled by the blit_shader.
4354 * TODO: get rid of this #if 0. */
4356 blit_supported
= device
->blitter
->blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4357 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4358 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
);
4360 blit_supported
= gl_info
->supported
[EXT_PALETTED_TEXTURE
] || gl_info
->supported
[ARB_FRAGMENT_PROGRAM
];
4362 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
4363 * texturing. Further also use conversion in case of color keying.
4364 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
4365 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
4366 * conflicts with this.
4368 if (!((blit_supported
&& device
->fb
.render_targets
&& surface
== device
->fb
.render_targets
[0]))
4369 || colorkey_active
|| !use_texturing
)
4371 format
->glFormat
= GL_RGBA
;
4372 format
->glInternal
= GL_RGBA
;
4373 format
->glType
= GL_UNSIGNED_BYTE
;
4374 format
->conv_byte_count
= 4;
4375 if (colorkey_active
)
4376 *convert
= CONVERT_PALETTED_CK
;
4378 *convert
= CONVERT_PALETTED
;
4382 case WINED3DFMT_B2G3R3_UNORM
:
4383 /* **********************
4384 GL_UNSIGNED_BYTE_3_3_2
4385 ********************** */
4386 if (colorkey_active
) {
4387 /* This texture format will never be used.. So do not care about color keying
4388 up until the point in time it will be needed :-) */
4389 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
4393 case WINED3DFMT_B5G6R5_UNORM
:
4394 if (colorkey_active
)
4396 *convert
= CONVERT_CK_565
;
4397 format
->glFormat
= GL_RGBA
;
4398 format
->glInternal
= GL_RGB5_A1
;
4399 format
->glType
= GL_UNSIGNED_SHORT_5_5_5_1
;
4400 format
->conv_byte_count
= 2;
4404 case WINED3DFMT_B5G5R5X1_UNORM
:
4405 if (colorkey_active
)
4407 *convert
= CONVERT_CK_5551
;
4408 format
->glFormat
= GL_BGRA
;
4409 format
->glInternal
= GL_RGB5_A1
;
4410 format
->glType
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
4411 format
->conv_byte_count
= 2;
4415 case WINED3DFMT_B8G8R8_UNORM
:
4416 if (colorkey_active
)
4418 *convert
= CONVERT_CK_RGB24
;
4419 format
->glFormat
= GL_RGBA
;
4420 format
->glInternal
= GL_RGBA8
;
4421 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
4422 format
->conv_byte_count
= 4;
4426 case WINED3DFMT_B8G8R8X8_UNORM
:
4427 if (colorkey_active
)
4429 *convert
= CONVERT_RGB32_888
;
4430 format
->glFormat
= GL_RGBA
;
4431 format
->glInternal
= GL_RGBA8
;
4432 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
4433 format
->conv_byte_count
= 4;
4444 void d3dfmt_p8_init_palette(const struct wined3d_surface
*surface
, BYTE table
[256][4], BOOL colorkey
)
4446 const struct wined3d_device
*device
= surface
->resource
.device
;
4447 const struct wined3d_palette
*pal
= surface
->palette
;
4448 BOOL index_in_alpha
= FALSE
;
4451 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4452 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4453 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4454 * duplicate entries. Store the color key in the unused alpha component to speed the
4455 * download up and to make conversion unneeded. */
4456 index_in_alpha
= primary_render_target_is_p8(device
);
4460 /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
4461 if (device
->wined3d
->flags
& WINED3D_PALETTE_PER_SURFACE
)
4463 ERR("This code should never get entered for DirectDraw!, expect problems\n");
4466 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4467 * there's no palette at this time. */
4468 for (i
= 0; i
< 256; i
++) table
[i
][3] = i
;
4473 /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
4474 * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
4475 * capability flag is present (wine does advertise this capability) */
4476 for (i
= 0; i
< 256; ++i
)
4478 table
[i
][0] = device
->palettes
[device
->currentPalette
][i
].peRed
;
4479 table
[i
][1] = device
->palettes
[device
->currentPalette
][i
].peGreen
;
4480 table
[i
][2] = device
->palettes
[device
->currentPalette
][i
].peBlue
;
4481 table
[i
][3] = device
->palettes
[device
->currentPalette
][i
].peFlags
;
4487 TRACE("Using surface palette %p\n", pal
);
4488 /* Get the surface's palette */
4489 for (i
= 0; i
< 256; ++i
)
4491 table
[i
][0] = pal
->palents
[i
].peRed
;
4492 table
[i
][1] = pal
->palents
[i
].peGreen
;
4493 table
[i
][2] = pal
->palents
[i
].peBlue
;
4495 /* When index_in_alpha is set the palette index is stored in the
4496 * alpha component. In case of a readback we can then read
4497 * GL_ALPHA. Color keying is handled in BltOverride using a
4498 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4499 * color key itself is passed to glAlphaFunc in other cases the
4500 * alpha component of pixels that should be masked away is set to 0. */
4505 else if (colorkey
&& (i
>= surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4506 && (i
<= surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4510 else if (pal
->flags
& WINEDDPCAPS_ALPHA
)
4512 table
[i
][3] = pal
->palents
[i
].peFlags
;
4522 static HRESULT
d3dfmt_convert_surface(const BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
,
4523 UINT height
, UINT outpitch
, CONVERT_TYPES convert
, struct wined3d_surface
*surface
)
4527 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src
, dst
, pitch
, height
, outpitch
, convert
, surface
);
4532 memcpy(dst
, src
, pitch
* height
);
4535 case CONVERT_PALETTED
:
4536 case CONVERT_PALETTED_CK
:
4541 d3dfmt_p8_init_palette(surface
, table
, (convert
== CONVERT_PALETTED_CK
));
4543 for (y
= 0; y
< height
; y
++)
4545 source
= src
+ pitch
* y
;
4546 dest
= dst
+ outpitch
* y
;
4547 /* This is an 1 bpp format, using the width here is fine */
4548 for (x
= 0; x
< width
; x
++) {
4549 BYTE color
= *source
++;
4550 *dest
++ = table
[color
][0];
4551 *dest
++ = table
[color
][1];
4552 *dest
++ = table
[color
][2];
4553 *dest
++ = table
[color
][3];
4559 case CONVERT_CK_565
:
4561 /* Converting the 565 format in 5551 packed to emulate color-keying.
4563 Note : in all these conversion, it would be best to average the averaging
4564 pixels to get the color of the pixel that will be color-keyed to
4565 prevent 'color bleeding'. This will be done later on if ever it is
4568 Note2: Nvidia documents say that their driver does not support alpha + color keying
4569 on the same surface and disables color keying in such a case
4575 TRACE("Color keyed 565\n");
4577 for (y
= 0; y
< height
; y
++) {
4578 Source
= (const WORD
*)(src
+ y
* pitch
);
4579 Dest
= (WORD
*) (dst
+ y
* outpitch
);
4580 for (x
= 0; x
< width
; x
++ ) {
4581 WORD color
= *Source
++;
4582 *Dest
= ((color
& 0xFFC0) | ((color
& 0x1F) << 1));
4583 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4584 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4592 case CONVERT_CK_5551
:
4594 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4598 TRACE("Color keyed 5551\n");
4599 for (y
= 0; y
< height
; y
++) {
4600 Source
= (const WORD
*)(src
+ y
* pitch
);
4601 Dest
= (WORD
*) (dst
+ y
* outpitch
);
4602 for (x
= 0; x
< width
; x
++ ) {
4603 WORD color
= *Source
++;
4605 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4606 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4609 *Dest
&= ~(1 << 15);
4616 case CONVERT_CK_RGB24
:
4618 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4620 for (y
= 0; y
< height
; y
++)
4622 source
= src
+ pitch
* y
;
4623 dest
= dst
+ outpitch
* y
;
4624 for (x
= 0; x
< width
; x
++) {
4625 DWORD color
= ((DWORD
)source
[0] << 16) + ((DWORD
)source
[1] << 8) + (DWORD
)source
[2] ;
4626 DWORD dstcolor
= color
<< 8;
4627 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4628 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4630 *(DWORD
*)dest
= dstcolor
;
4638 case CONVERT_RGB32_888
:
4640 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4642 for (y
= 0; y
< height
; y
++)
4644 source
= src
+ pitch
* y
;
4645 dest
= dst
+ outpitch
* y
;
4646 for (x
= 0; x
< width
; x
++) {
4647 DWORD color
= 0xffffff & *(const DWORD
*)source
;
4648 DWORD dstcolor
= color
<< 8;
4649 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4650 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4652 *(DWORD
*)dest
= dstcolor
;
4661 ERR("Unsupported conversion type %#x.\n", convert
);
4666 BOOL
palette9_changed(struct wined3d_surface
*surface
)
4668 struct wined3d_device
*device
= surface
->resource
.device
;
4670 if (surface
->palette
|| (surface
->resource
.format
->id
!= WINED3DFMT_P8_UINT
4671 && surface
->resource
.format
->id
!= WINED3DFMT_P8_UINT_A8_UNORM
))
4673 /* If a ddraw-style palette is attached assume no d3d9 palette change.
4674 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
4679 if (surface
->palette9
)
4681 if (!memcmp(surface
->palette9
, device
->palettes
[device
->currentPalette
], sizeof(PALETTEENTRY
) * 256))
4688 surface
->palette9
= HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
4690 memcpy(surface
->palette9
, device
->palettes
[device
->currentPalette
], sizeof(PALETTEENTRY
) * 256);
4695 void flip_surface(struct wined3d_surface
*front
, struct wined3d_surface
*back
)
4697 /* Flip the surface contents */
4702 front
->hDC
= back
->hDC
;
4706 /* Flip the DIBsection */
4709 BOOL hasDib
= front
->flags
& SFLAG_DIBSECTION
;
4710 tmp
= front
->dib
.DIBsection
;
4711 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
4712 back
->dib
.DIBsection
= tmp
;
4714 if (back
->flags
& SFLAG_DIBSECTION
) front
->flags
|= SFLAG_DIBSECTION
;
4715 else front
->flags
&= ~SFLAG_DIBSECTION
;
4716 if (hasDib
) back
->flags
|= SFLAG_DIBSECTION
;
4717 else back
->flags
&= ~SFLAG_DIBSECTION
;
4720 /* Flip the surface data */
4724 tmp
= front
->dib
.bitmap_data
;
4725 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
4726 back
->dib
.bitmap_data
= tmp
;
4728 tmp
= front
->resource
.allocatedMemory
;
4729 front
->resource
.allocatedMemory
= back
->resource
.allocatedMemory
;
4730 back
->resource
.allocatedMemory
= tmp
;
4732 tmp
= front
->resource
.heapMemory
;
4733 front
->resource
.heapMemory
= back
->resource
.heapMemory
;
4734 back
->resource
.heapMemory
= tmp
;
4739 GLuint tmp_pbo
= front
->pbo
;
4740 front
->pbo
= back
->pbo
;
4741 back
->pbo
= tmp_pbo
;
4744 /* client_memory should not be different, but just in case */
4747 tmp
= front
->dib
.client_memory
;
4748 front
->dib
.client_memory
= back
->dib
.client_memory
;
4749 back
->dib
.client_memory
= tmp
;
4752 /* Flip the opengl texture */
4756 tmp
= back
->texture_name
;
4757 back
->texture_name
= front
->texture_name
;
4758 front
->texture_name
= tmp
;
4760 tmp
= back
->texture_name_srgb
;
4761 back
->texture_name_srgb
= front
->texture_name_srgb
;
4762 front
->texture_name_srgb
= tmp
;
4764 tmp
= back
->rb_multisample
;
4765 back
->rb_multisample
= front
->rb_multisample
;
4766 front
->rb_multisample
= tmp
;
4768 tmp
= back
->rb_resolved
;
4769 back
->rb_resolved
= front
->rb_resolved
;
4770 front
->rb_resolved
= tmp
;
4772 resource_unload(&back
->resource
);
4773 resource_unload(&front
->resource
);
4777 DWORD tmp_flags
= back
->flags
;
4778 back
->flags
= front
->flags
;
4779 front
->flags
= tmp_flags
;
4783 /* Does a direct frame buffer -> texture copy. Stretching is done with single
4784 * pixel copy calls. */
4785 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
4786 const RECT
*src_rect
, const RECT
*dst_rect_in
, WINED3DTEXTUREFILTERTYPE Filter
)
4788 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4791 struct wined3d_context
*context
;
4792 BOOL upsidedown
= FALSE
;
4793 RECT dst_rect
= *dst_rect_in
;
4795 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4796 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4798 if(dst_rect
.top
> dst_rect
.bottom
) {
4799 UINT tmp
= dst_rect
.bottom
;
4800 dst_rect
.bottom
= dst_rect
.top
;
4805 context
= context_acquire(device
, src_surface
);
4806 context_apply_blit_state(context
, device
);
4807 surface_internal_preload(dst_surface
, SRGB_RGB
);
4810 /* Bind the target texture */
4811 context_bind_texture(context
, dst_surface
->texture_target
, dst_surface
->texture_name
);
4812 if (surface_is_offscreen(src_surface
))
4814 TRACE("Reading from an offscreen target\n");
4815 upsidedown
= !upsidedown
;
4816 glReadBuffer(device
->offscreenBuffer
);
4820 glReadBuffer(surface_get_gl_buffer(src_surface
));
4822 checkGLcall("glReadBuffer");
4824 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
4825 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
4827 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4829 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4831 if(Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
) {
4832 ERR("Texture filtering not supported in direct blit\n");
4835 else if ((Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
)
4836 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
4838 ERR("Texture filtering not supported in direct blit\n");
4842 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4843 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
4845 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
4847 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4848 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
4849 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
4850 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
4854 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
4855 /* I have to process this row by row to swap the image,
4856 * otherwise it would be upside down, so stretching in y direction
4857 * doesn't cost extra time
4859 * However, stretching in x direction can be avoided if not necessary
4861 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
4862 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4864 /* Well, that stuff works, but it's very slow.
4865 * find a better way instead
4869 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
4871 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4872 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
4873 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
4878 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4879 dst_rect
.left
/* x offset */, row
/* y offset */,
4880 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
4884 checkGLcall("glCopyTexSubImage2D");
4887 context_release(context
);
4889 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
4890 * path is never entered
4892 surface_modify_location(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
4895 /* Uses the hardware to stretch and flip the image */
4896 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
4897 const RECT
*src_rect
, const RECT
*dst_rect_in
, WINED3DTEXTUREFILTERTYPE Filter
)
4899 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4900 struct wined3d_swapchain
*src_swapchain
= NULL
;
4901 GLuint src
, backup
= 0;
4902 float left
, right
, top
, bottom
; /* Texture coordinates */
4903 UINT fbwidth
= src_surface
->resource
.width
;
4904 UINT fbheight
= src_surface
->resource
.height
;
4905 struct wined3d_context
*context
;
4906 GLenum drawBuffer
= GL_BACK
;
4907 GLenum texture_target
;
4908 BOOL noBackBufferBackup
;
4910 BOOL upsidedown
= FALSE
;
4911 RECT dst_rect
= *dst_rect_in
;
4913 TRACE("Using hwstretch blit\n");
4914 /* Activate the Proper context for reading from the source surface, set it up for blitting */
4915 context
= context_acquire(device
, src_surface
);
4916 context_apply_blit_state(context
, device
);
4917 surface_internal_preload(dst_surface
, SRGB_RGB
);
4919 src_offscreen
= surface_is_offscreen(src_surface
);
4920 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
4921 if (!noBackBufferBackup
&& !src_surface
->texture_name
)
4923 /* Get it a description */
4924 surface_internal_preload(src_surface
, SRGB_RGB
);
4928 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
4929 * This way we don't have to wait for the 2nd readback to finish to leave this function.
4931 if (context
->aux_buffers
>= 2)
4933 /* Got more than one aux buffer? Use the 2nd aux buffer */
4934 drawBuffer
= GL_AUX1
;
4936 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
4938 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
4939 drawBuffer
= GL_AUX0
;
4942 if(noBackBufferBackup
) {
4943 glGenTextures(1, &backup
);
4944 checkGLcall("glGenTextures");
4945 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
4946 texture_target
= GL_TEXTURE_2D
;
4948 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
4949 * we are reading from the back buffer, the backup can be used as source texture
4951 texture_target
= src_surface
->texture_target
;
4952 context_bind_texture(context
, texture_target
, src_surface
->texture_name
);
4953 glEnable(texture_target
);
4954 checkGLcall("glEnable(texture_target)");
4956 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
4957 src_surface
->flags
&= ~SFLAG_INTEXTURE
;
4960 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4961 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4963 if(dst_rect
.top
> dst_rect
.bottom
) {
4964 UINT tmp
= dst_rect
.bottom
;
4965 dst_rect
.bottom
= dst_rect
.top
;
4972 TRACE("Reading from an offscreen target\n");
4973 upsidedown
= !upsidedown
;
4974 glReadBuffer(device
->offscreenBuffer
);
4978 glReadBuffer(surface_get_gl_buffer(src_surface
));
4981 /* TODO: Only back up the part that will be overwritten */
4982 glCopyTexSubImage2D(texture_target
, 0,
4983 0, 0 /* read offsets */,
4988 checkGLcall("glCopyTexSubImage2D");
4990 /* No issue with overriding these - the sampler is dirty due to blit usage */
4991 glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
,
4992 wined3d_gl_mag_filter(magLookup
, Filter
));
4993 checkGLcall("glTexParameteri");
4994 glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
4995 wined3d_gl_min_mip_filter(minMipLookup
, Filter
, WINED3DTEXF_NONE
));
4996 checkGLcall("glTexParameteri");
4998 if (src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
4999 src_swapchain
= src_surface
->container
.u
.swapchain
;
5000 if (!src_swapchain
|| src_surface
== src_swapchain
->back_buffers
[0])
5002 src
= backup
? backup
: src_surface
->texture_name
;
5006 glReadBuffer(GL_FRONT
);
5007 checkGLcall("glReadBuffer(GL_FRONT)");
5009 glGenTextures(1, &src
);
5010 checkGLcall("glGenTextures(1, &src)");
5011 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
5013 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5014 * out for power of 2 sizes
5016 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
5017 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
5018 checkGLcall("glTexImage2D");
5019 glCopyTexSubImage2D(GL_TEXTURE_2D
, 0,
5020 0, 0 /* read offsets */,
5025 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5026 checkGLcall("glTexParameteri");
5027 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5028 checkGLcall("glTexParameteri");
5030 glReadBuffer(GL_BACK
);
5031 checkGLcall("glReadBuffer(GL_BACK)");
5033 if(texture_target
!= GL_TEXTURE_2D
) {
5034 glDisable(texture_target
);
5035 glEnable(GL_TEXTURE_2D
);
5036 texture_target
= GL_TEXTURE_2D
;
5039 checkGLcall("glEnd and previous");
5041 left
= src_rect
->left
;
5042 right
= src_rect
->right
;
5046 top
= src_surface
->resource
.height
- src_rect
->top
;
5047 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
5051 top
= src_surface
->resource
.height
- src_rect
->bottom
;
5052 bottom
= src_surface
->resource
.height
- src_rect
->top
;
5055 if (src_surface
->flags
& SFLAG_NORMCOORD
)
5057 left
/= src_surface
->pow2Width
;
5058 right
/= src_surface
->pow2Width
;
5059 top
/= src_surface
->pow2Height
;
5060 bottom
/= src_surface
->pow2Height
;
5063 /* draw the source texture stretched and upside down. The correct surface is bound already */
5064 glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
5065 glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
5067 context_set_draw_buffer(context
, drawBuffer
);
5068 glReadBuffer(drawBuffer
);
5072 glTexCoord2f(left
, bottom
);
5076 glTexCoord2f(left
, top
);
5077 glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
5080 glTexCoord2f(right
, top
);
5081 glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
5084 glTexCoord2f(right
, bottom
);
5085 glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
5087 checkGLcall("glEnd and previous");
5089 if (texture_target
!= dst_surface
->texture_target
)
5091 glDisable(texture_target
);
5092 glEnable(dst_surface
->texture_target
);
5093 texture_target
= dst_surface
->texture_target
;
5096 /* Now read the stretched and upside down image into the destination texture */
5097 context_bind_texture(context
, texture_target
, dst_surface
->texture_name
);
5098 glCopyTexSubImage2D(texture_target
,
5100 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
5101 0, 0, /* We blitted the image to the origin */
5102 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
5103 checkGLcall("glCopyTexSubImage2D");
5105 if(drawBuffer
== GL_BACK
) {
5106 /* Write the back buffer backup back */
5108 if(texture_target
!= GL_TEXTURE_2D
) {
5109 glDisable(texture_target
);
5110 glEnable(GL_TEXTURE_2D
);
5111 texture_target
= GL_TEXTURE_2D
;
5113 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
5117 if (texture_target
!= src_surface
->texture_target
)
5119 glDisable(texture_target
);
5120 glEnable(src_surface
->texture_target
);
5121 texture_target
= src_surface
->texture_target
;
5123 context_bind_texture(context
, src_surface
->texture_target
, src_surface
->texture_name
);
5128 glTexCoord2f(0.0f
, 0.0f
);
5129 glVertex2i(0, fbheight
);
5132 glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
5136 glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
5137 (float)fbheight
/ (float)src_surface
->pow2Height
);
5138 glVertex2i(fbwidth
, 0);
5141 glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
5142 glVertex2i(fbwidth
, fbheight
);
5145 glDisable(texture_target
);
5146 checkGLcall("glDisable(texture_target)");
5149 if (src
!= src_surface
->texture_name
&& src
!= backup
)
5151 glDeleteTextures(1, &src
);
5152 checkGLcall("glDeleteTextures(1, &src)");
5155 glDeleteTextures(1, &backup
);
5156 checkGLcall("glDeleteTextures(1, &backup)");
5161 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5163 context_release(context
);
5165 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5166 * path is never entered
5168 surface_modify_location(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
5171 /* Front buffer coordinates are always full screen coordinates, but our GL
5172 * drawable is limited to the window's client area. The sysmem and texture
5173 * copies do have the full screen size. Note that GL has a bottom-left
5174 * origin, while D3D has a top-left origin. */
5175 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
5177 UINT drawable_height
;
5179 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
5180 && surface
== surface
->container
.u
.swapchain
->front_buffer
)
5182 POINT offset
= {0, 0};
5185 ScreenToClient(window
, &offset
);
5186 OffsetRect(rect
, offset
.x
, offset
.y
);
5188 GetClientRect(window
, &windowsize
);
5189 drawable_height
= windowsize
.bottom
- windowsize
.top
;
5193 drawable_height
= surface
->resource
.height
;
5196 rect
->top
= drawable_height
- rect
->top
;
5197 rect
->bottom
= drawable_height
- rect
->bottom
;
5200 static void surface_blt_to_drawable(struct wined3d_device
*device
,
5201 WINED3DTEXTUREFILTERTYPE filter
, BOOL color_key
,
5202 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
5203 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
5205 struct wined3d_context
*context
;
5206 RECT src_rect
, dst_rect
;
5208 src_rect
= *src_rect_in
;
5209 dst_rect
= *dst_rect_in
;
5211 /* Make sure the surface is up-to-date. This should probably use
5212 * surface_load_location() and worry about the destination surface too,
5213 * unless we're overwriting it completely. */
5214 surface_internal_preload(src_surface
, SRGB_RGB
);
5216 /* Activate the destination context, set it up for blitting */
5217 context
= context_acquire(device
, dst_surface
);
5218 context_apply_blit_state(context
, device
);
5220 if (!surface_is_offscreen(dst_surface
))
5221 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
5223 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
);
5229 glEnable(GL_ALPHA_TEST
);
5230 checkGLcall("glEnable(GL_ALPHA_TEST)");
5232 /* When the primary render target uses P8, the alpha component
5233 * contains the palette index. Which means that the colorkey is one of
5234 * the palette entries. In other cases pixels that should be masked
5235 * away have alpha set to 0. */
5236 if (primary_render_target_is_p8(device
))
5237 glAlphaFunc(GL_NOTEQUAL
, (float)src_surface
->SrcBltCKey
.dwColorSpaceLowValue
/ 256.0f
);
5239 glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
5240 checkGLcall("glAlphaFunc");
5244 glDisable(GL_ALPHA_TEST
);
5245 checkGLcall("glDisable(GL_ALPHA_TEST)");
5248 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
5252 glDisable(GL_ALPHA_TEST
);
5253 checkGLcall("glDisable(GL_ALPHA_TEST)");
5258 /* Leave the opengl state valid for blitting */
5259 device
->blitter
->unset_shader(context
->gl_info
);
5261 if (wined3d_settings
.strict_draw_ordering
5262 || (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
5263 && (dst_surface
->container
.u
.swapchain
->front_buffer
== dst_surface
)))
5264 wglFlush(); /* Flush to ensure ordering across contexts. */
5266 context_release(context
);
5269 /* Do not call while under the GL lock. */
5270 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const WINED3DCOLORVALUE
*color
)
5272 struct wined3d_device
*device
= s
->resource
.device
;
5273 const struct blit_shader
*blitter
;
5275 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_FILL
,
5276 NULL
, 0, 0, NULL
, rect
, s
->resource
.usage
, s
->resource
.pool
, s
->resource
.format
);
5279 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5280 return WINED3DERR_INVALIDCALL
;
5283 return blitter
->color_fill(device
, s
, rect
, color
);
5286 /* Do not call while under the GL lock. */
5287 static HRESULT
IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5288 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
,
5289 WINED3DTEXTUREFILTERTYPE Filter
)
5291 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5292 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
5293 struct wined3d_swapchain
*srcSwapchain
= NULL
, *dstSwapchain
= NULL
;
5295 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5296 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5297 flags
, DDBltFx
, debug_d3dtexturefiltertype(Filter
));
5299 /* Get the swapchain. One of the surfaces has to be a primary surface */
5300 if (dst_surface
->resource
.pool
== WINED3DPOOL_SYSTEMMEM
)
5302 WARN("Destination is in sysmem, rejecting gl blt\n");
5303 return WINED3DERR_INVALIDCALL
;
5306 if (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
5307 dstSwapchain
= dst_surface
->container
.u
.swapchain
;
5311 if (src_surface
->resource
.pool
== WINED3DPOOL_SYSTEMMEM
)
5313 WARN("Src is in sysmem, rejecting gl blt\n");
5314 return WINED3DERR_INVALIDCALL
;
5317 if (src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
5318 srcSwapchain
= src_surface
->container
.u
.swapchain
;
5321 /* Early sort out of cases where no render target is used */
5322 if (!dstSwapchain
&& !srcSwapchain
5323 && src_surface
!= device
->fb
.render_targets
[0]
5324 && dst_surface
!= device
->fb
.render_targets
[0])
5326 TRACE("No surface is render target, not using hardware blit.\n");
5327 return WINED3DERR_INVALIDCALL
;
5330 /* No destination color keying supported */
5331 if (flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
))
5333 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5334 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5335 return WINED3DERR_INVALIDCALL
;
5338 if (dstSwapchain
&& dstSwapchain
== srcSwapchain
)
5340 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5341 return WINED3DERR_INVALIDCALL
;
5344 if (dstSwapchain
&& srcSwapchain
)
5346 FIXME("Implement hardware blit between two different swapchains\n");
5347 return WINED3DERR_INVALIDCALL
;
5352 /* Handled with regular texture -> swapchain blit */
5353 if (src_surface
== device
->fb
.render_targets
[0])
5354 TRACE("Blit from active render target to a swapchain\n");
5356 else if (srcSwapchain
&& dst_surface
== device
->fb
.render_targets
[0])
5358 FIXME("Implement blit from a swapchain to the active render target\n");
5359 return WINED3DERR_INVALIDCALL
;
5362 if ((srcSwapchain
|| src_surface
== device
->fb
.render_targets
[0]) && !dstSwapchain
)
5364 /* Blit from render target to texture */
5367 /* P8 read back is not implemented */
5368 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
5369 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
5371 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5372 return WINED3DERR_INVALIDCALL
;
5375 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
5377 TRACE("Color keying not supported by frame buffer to texture blit\n");
5378 return WINED3DERR_INVALIDCALL
;
5379 /* Destination color key is checked above */
5382 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
5387 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5388 * flip the image nor scale it.
5390 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5391 * -> If the app wants a image width an unscaled width, copy it line per line
5392 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5393 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5394 * back buffer. This is slower than reading line per line, thus not used for flipping
5395 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5396 * pixel by pixel. */
5397 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
5398 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
5400 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
5401 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, Filter
);
5403 TRACE("Using hardware stretching to flip / stretch the texture\n");
5404 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, Filter
);
5407 if (!(dst_surface
->flags
& SFLAG_DONOTFREE
))
5409 HeapFree(GetProcessHeap(), 0, dst_surface
->resource
.heapMemory
);
5410 dst_surface
->resource
.allocatedMemory
= NULL
;
5411 dst_surface
->resource
.heapMemory
= NULL
;
5415 dst_surface
->flags
&= ~SFLAG_INSYSMEM
;
5420 else if (src_surface
)
5422 /* Blit from offscreen surface to render target */
5423 DWORD oldCKeyFlags
= src_surface
->CKeyFlags
;
5424 WINEDDCOLORKEY oldBltCKey
= src_surface
->SrcBltCKey
;
5426 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
5428 if (!device
->blitter
->blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5429 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5430 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5432 FIXME("Unsupported blit operation falling back to software\n");
5433 return WINED3DERR_INVALIDCALL
;
5436 /* Color keying: Check if we have to do a color keyed blt,
5437 * and if not check if a color key is activated.
5439 * Just modify the color keying parameters in the surface and restore them afterwards
5440 * The surface keeps track of the color key last used to load the opengl surface.
5441 * PreLoad will catch the change to the flags and color key and reload if necessary.
5443 if (flags
& WINEDDBLT_KEYSRC
)
5445 /* Use color key from surface */
5447 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
5449 /* Use color key from DDBltFx */
5450 src_surface
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
5451 src_surface
->SrcBltCKey
= DDBltFx
->ddckSrcColorkey
;
5455 /* Do not use color key */
5456 src_surface
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
5459 surface_blt_to_drawable(device
, Filter
, flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
),
5460 src_surface
, src_rect
, dst_surface
, dst_rect
);
5462 /* Restore the color key parameters */
5463 src_surface
->CKeyFlags
= oldCKeyFlags
;
5464 src_surface
->SrcBltCKey
= oldBltCKey
;
5466 surface_modify_location(dst_surface
, dst_surface
->draw_binding
, TRUE
);
5471 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5472 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5473 return WINED3DERR_INVALIDCALL
;
5476 /* GL locking is done by the caller */
5477 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
5478 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
5480 struct wined3d_device
*device
= surface
->resource
.device
;
5481 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
5482 GLint compare_mode
= GL_NONE
;
5483 struct blt_info info
;
5484 GLint old_binding
= 0;
5487 glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
5489 glDisable(GL_CULL_FACE
);
5490 glDisable(GL_BLEND
);
5491 glDisable(GL_ALPHA_TEST
);
5492 glDisable(GL_SCISSOR_TEST
);
5493 glDisable(GL_STENCIL_TEST
);
5494 glEnable(GL_DEPTH_TEST
);
5495 glDepthFunc(GL_ALWAYS
);
5496 glDepthMask(GL_TRUE
);
5497 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
5498 glViewport(x
, y
, w
, h
);
5500 SetRect(&rect
, 0, h
, w
, 0);
5501 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
5502 context_active_texture(context
, context
->gl_info
, 0);
5503 glGetIntegerv(info
.binding
, &old_binding
);
5504 glBindTexture(info
.bind_target
, texture
);
5505 if (gl_info
->supported
[ARB_SHADOW
])
5507 glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
5508 if (compare_mode
!= GL_NONE
) glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
5511 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
5512 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
5514 glBegin(GL_TRIANGLE_STRIP
);
5515 glTexCoord3fv(info
.coords
[0]);
5516 glVertex2f(-1.0f
, -1.0f
);
5517 glTexCoord3fv(info
.coords
[1]);
5518 glVertex2f(1.0f
, -1.0f
);
5519 glTexCoord3fv(info
.coords
[2]);
5520 glVertex2f(-1.0f
, 1.0f
);
5521 glTexCoord3fv(info
.coords
[3]);
5522 glVertex2f(1.0f
, 1.0f
);
5525 if (compare_mode
!= GL_NONE
) glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
5526 glBindTexture(info
.bind_target
, old_binding
);
5530 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
5533 void surface_modify_ds_location(struct wined3d_surface
*surface
,
5534 DWORD location
, UINT w
, UINT h
)
5536 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
5538 if (location
& ~SFLAG_DS_LOCATIONS
)
5539 FIXME("Invalid location (%#x) specified.\n", location
);
5541 surface
->ds_current_size
.cx
= w
;
5542 surface
->ds_current_size
.cy
= h
;
5543 surface
->flags
&= ~SFLAG_DS_LOCATIONS
;
5544 surface
->flags
|= location
;
5547 /* Context activation is done by the caller. */
5548 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
5550 struct wined3d_device
*device
= surface
->resource
.device
;
5553 TRACE("surface %p, new location %#x.\n", surface
, location
);
5555 /* TODO: Make this work for modes other than FBO */
5556 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
5558 if (!(surface
->flags
& location
))
5560 w
= surface
->ds_current_size
.cx
;
5561 h
= surface
->ds_current_size
.cy
;
5562 surface
->ds_current_size
.cx
= 0;
5563 surface
->ds_current_size
.cy
= 0;
5567 w
= surface
->resource
.width
;
5568 h
= surface
->resource
.height
;
5571 if (surface
->ds_current_size
.cx
== surface
->resource
.width
5572 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
5574 TRACE("Location (%#x) is already up to date.\n", location
);
5578 if (surface
->current_renderbuffer
)
5580 FIXME("Not supported with fixed up depth stencil.\n");
5584 if (!(surface
->flags
& SFLAG_DS_LOCATIONS
))
5586 /* This mostly happens when a depth / stencil is used without being
5587 * cleared first. In principle we could upload from sysmem, or
5588 * explicitly clear before first usage. For the moment there don't
5589 * appear to be a lot of applications depending on this, so a FIXME
5591 FIXME("No up to date depth stencil location.\n");
5592 surface
->flags
|= location
;
5593 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5594 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5598 if (location
== SFLAG_DS_OFFSCREEN
)
5600 GLint old_binding
= 0;
5603 /* The render target is allowed to be smaller than the depth/stencil
5604 * buffer, so the onscreen depth/stencil buffer is potentially smaller
5605 * than the offscreen surface. Don't overwrite the offscreen surface
5606 * with undefined data. */
5607 w
= min(w
, context
->swapchain
->presentParms
.BackBufferWidth
);
5608 h
= min(h
, context
->swapchain
->presentParms
.BackBufferHeight
);
5610 TRACE("Copying onscreen depth buffer to depth texture.\n");
5614 if (!device
->depth_blt_texture
)
5616 glGenTextures(1, &device
->depth_blt_texture
);
5619 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5620 * directly on the FBO texture. That's because we need to flip. */
5621 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5622 context
->swapchain
->front_buffer
, NULL
, SFLAG_INDRAWABLE
);
5623 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
5625 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
5626 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
5630 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
5631 bind_target
= GL_TEXTURE_2D
;
5633 glBindTexture(bind_target
, device
->depth_blt_texture
);
5634 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
5635 * internal format, because the internal format might include stencil
5636 * data. In principle we should copy stencil data as well, but unless
5637 * the driver supports stencil export it's hard to do, and doesn't
5638 * seem to be needed in practice. If the hardware doesn't support
5639 * writing stencil data, the glCopyTexImage2D() call might trigger
5640 * software fallbacks. */
5641 glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
5642 glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5643 glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5644 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
5645 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
5646 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
5647 glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
5648 glBindTexture(bind_target
, old_binding
);
5650 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5651 NULL
, surface
, SFLAG_INTEXTURE
);
5652 context_set_draw_buffer(context
, GL_NONE
);
5653 glReadBuffer(GL_NONE
);
5655 /* Do the actual blit */
5656 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
5657 checkGLcall("depth_blt");
5659 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
5663 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5665 else if (location
== SFLAG_DS_ONSCREEN
)
5667 TRACE("Copying depth texture to onscreen depth buffer.\n");
5671 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5672 context
->swapchain
->front_buffer
, NULL
, SFLAG_INDRAWABLE
);
5673 surface_depth_blt(surface
, context
, surface
->texture_name
,
5674 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
5675 checkGLcall("depth_blt");
5677 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
5681 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5685 ERR("Invalid location (%#x) specified.\n", location
);
5688 surface
->flags
|= location
;
5689 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5690 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5693 void surface_modify_location(struct wined3d_surface
*surface
, DWORD location
, BOOL persistent
)
5695 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
5696 struct wined3d_surface
*overlay
;
5698 TRACE("surface %p, location %s, persistent %#x.\n",
5699 surface
, debug_surflocation(location
), persistent
);
5701 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& surface_is_offscreen(surface
)
5702 && (location
& SFLAG_INDRAWABLE
))
5703 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
5705 if (location
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)
5706 && gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
5707 location
|= (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
);
5711 if (((surface
->flags
& SFLAG_INTEXTURE
) && !(location
& SFLAG_INTEXTURE
))
5712 || ((surface
->flags
& SFLAG_INSRGBTEX
) && !(location
& SFLAG_INSRGBTEX
)))
5714 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
5716 TRACE("Passing to container.\n");
5717 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
5720 surface
->flags
&= ~SFLAG_LOCATIONS
;
5721 surface
->flags
|= location
;
5723 /* Redraw emulated overlays, if any */
5724 if (location
& SFLAG_INDRAWABLE
&& !list_empty(&surface
->overlays
))
5726 LIST_FOR_EACH_ENTRY(overlay
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
5728 overlay
->surface_ops
->surface_draw_overlay(overlay
);
5734 if ((surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)) && (location
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)))
5736 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
5738 TRACE("Passing to container\n");
5739 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
5742 surface
->flags
&= ~location
;
5745 if (!(surface
->flags
& SFLAG_LOCATIONS
))
5747 ERR("Surface %p does not have any up to date location.\n", surface
);
5751 static DWORD
resource_access_from_location(DWORD location
)
5755 case SFLAG_INSYSMEM
:
5756 return WINED3D_RESOURCE_ACCESS_CPU
;
5758 case SFLAG_INDRAWABLE
:
5759 case SFLAG_INSRGBTEX
:
5760 case SFLAG_INTEXTURE
:
5761 case SFLAG_INRB_MULTISAMPLE
:
5762 case SFLAG_INRB_RESOLVED
:
5763 return WINED3D_RESOURCE_ACCESS_GPU
;
5766 FIXME("Unhandled location %#x.\n", location
);
5771 static void surface_load_sysmem(struct wined3d_surface
*surface
,
5772 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
)
5774 surface_prepare_system_memory(surface
);
5776 /* Download the surface to system memory. */
5777 if (surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
))
5779 struct wined3d_device
*device
= surface
->resource
.device
;
5780 struct wined3d_context
*context
;
5782 /* TODO: Use already acquired context when possible. */
5783 context
= context_acquire(device
, NULL
);
5785 surface_bind_and_dirtify(surface
, context
, !(surface
->flags
& SFLAG_INTEXTURE
));
5786 surface_download_data(surface
, gl_info
);
5788 context_release(context
);
5793 /* Note: It might be faster to download into a texture first. */
5794 read_from_framebuffer(surface
, rect
, surface
->resource
.allocatedMemory
,
5795 wined3d_surface_get_pitch(surface
));
5798 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
5799 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
)
5801 struct wined3d_device
*device
= surface
->resource
.device
;
5802 struct wined3d_format format
;
5803 CONVERT_TYPES convert
;
5807 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& surface_is_offscreen(surface
))
5809 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
5810 return WINED3DERR_INVALIDCALL
;
5813 if (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
)
5814 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
5816 if (surface
->flags
& SFLAG_INTEXTURE
)
5820 surface_get_rect(surface
, rect
, &r
);
5821 surface_blt_to_drawable(device
, WINED3DTEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
5826 if ((surface
->flags
& SFLAG_LOCATIONS
) == SFLAG_INSRGBTEX
)
5828 /* This needs colorspace conversion from sRGB to RGB. We take the slow
5829 * path through sysmem. */
5830 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5833 d3dfmt_get_conv(surface
, FALSE
, FALSE
, &format
, &convert
);
5835 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
5836 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
5838 if ((convert
!= NO_CONVERSION
) && (surface
->flags
& SFLAG_PBO
))
5840 struct wined3d_context
*context
;
5842 TRACE("Removing the pbo attached to surface %p.\n", surface
);
5844 /* TODO: Use already acquired context when possible. */
5845 context
= context_acquire(device
, NULL
);
5847 surface_remove_pbo(surface
, gl_info
);
5849 context_release(context
);
5852 if ((convert
!= NO_CONVERSION
) && surface
->resource
.allocatedMemory
)
5854 UINT height
= surface
->resource
.height
;
5855 UINT width
= surface
->resource
.width
;
5856 UINT src_pitch
, dst_pitch
;
5858 byte_count
= format
.conv_byte_count
;
5859 src_pitch
= wined3d_surface_get_pitch(surface
);
5861 /* Stick to the alignment for the converted surface too, makes it
5862 * easier to load the surface. */
5863 dst_pitch
= width
* byte_count
;
5864 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
5866 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
5868 ERR("Out of memory (%u).\n", dst_pitch
* height
);
5869 return E_OUTOFMEMORY
;
5872 d3dfmt_convert_surface(surface
->resource
.allocatedMemory
, mem
,
5873 src_pitch
, width
, height
, dst_pitch
, convert
, surface
);
5875 surface
->flags
|= SFLAG_CONVERTED
;
5879 surface
->flags
&= ~SFLAG_CONVERTED
;
5880 mem
= surface
->resource
.allocatedMemory
;
5881 byte_count
= format
.byte_count
;
5884 flush_to_framebuffer_drawpixels(surface
, rect
, format
.glFormat
, format
.glType
, byte_count
, mem
);
5886 /* Don't delete PBO memory. */
5887 if ((mem
!= surface
->resource
.allocatedMemory
) && !(surface
->flags
& SFLAG_PBO
))
5888 HeapFree(GetProcessHeap(), 0, mem
);
5893 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
5894 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
, BOOL srgb
)
5896 const DWORD attach_flags
= WINED3DFMT_FLAG_FBO_ATTACHABLE
| WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
;
5897 RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
5898 struct wined3d_device
*device
= surface
->resource
.device
;
5899 struct wined3d_context
*context
;
5900 UINT width
, src_pitch
, dst_pitch
;
5901 struct wined3d_bo_address data
;
5902 struct wined3d_format format
;
5903 POINT dst_point
= {0, 0};
5904 CONVERT_TYPES convert
;
5907 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
5908 && surface_is_offscreen(surface
)
5909 && (surface
->flags
& SFLAG_INDRAWABLE
))
5911 read_from_framebuffer_texture(surface
, srgb
);
5916 if (surface
->flags
& (SFLAG_INSRGBTEX
| SFLAG_INTEXTURE
)
5917 && (surface
->resource
.format
->flags
& attach_flags
) == attach_flags
5918 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5919 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
5920 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
5923 surface_blt_fbo(device
, WINED3DTEXF_POINT
, surface
, SFLAG_INTEXTURE
,
5924 &src_rect
, surface
, SFLAG_INSRGBTEX
, &src_rect
);
5926 surface_blt_fbo(device
, WINED3DTEXF_POINT
, surface
, SFLAG_INSRGBTEX
,
5927 &src_rect
, surface
, SFLAG_INTEXTURE
, &src_rect
);
5932 /* Upload from system memory */
5934 d3dfmt_get_conv(surface
, TRUE
/* We need color keying */,
5935 TRUE
/* We will use textures */, &format
, &convert
);
5939 if ((surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSYSMEM
)) == SFLAG_INTEXTURE
)
5941 /* Performance warning... */
5942 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
5943 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5948 if ((surface
->flags
& (SFLAG_INSRGBTEX
| SFLAG_INSYSMEM
)) == SFLAG_INSRGBTEX
)
5950 /* Performance warning... */
5951 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
5952 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5956 if (!(surface
->flags
& SFLAG_INSYSMEM
))
5958 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
5959 /* Lets hope we get it from somewhere... */
5960 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5963 /* TODO: Use already acquired context when possible. */
5964 context
= context_acquire(device
, NULL
);
5966 surface_prepare_texture(surface
, context
, srgb
);
5967 surface_bind_and_dirtify(surface
, context
, srgb
);
5969 if (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
)
5971 surface
->flags
|= SFLAG_GLCKEY
;
5972 surface
->glCKey
= surface
->SrcBltCKey
;
5974 else surface
->flags
&= ~SFLAG_GLCKEY
;
5976 width
= surface
->resource
.width
;
5977 src_pitch
= wined3d_surface_get_pitch(surface
);
5979 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
5980 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
5982 if ((convert
!= NO_CONVERSION
|| format
.convert
) && (surface
->flags
& SFLAG_PBO
))
5984 TRACE("Removing the pbo attached to surface %p.\n", surface
);
5985 surface_remove_pbo(surface
, gl_info
);
5990 /* This code is entered for texture formats which need a fixup. */
5991 UINT height
= surface
->resource
.height
;
5993 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
5994 dst_pitch
= width
* format
.conv_byte_count
;
5995 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
5997 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
5999 ERR("Out of memory (%u).\n", dst_pitch
* height
);
6000 context_release(context
);
6001 return E_OUTOFMEMORY
;
6003 format
.convert(surface
->resource
.allocatedMemory
, mem
, src_pitch
, width
, height
);
6005 else if (convert
!= NO_CONVERSION
&& surface
->resource
.allocatedMemory
)
6007 /* This code is only entered for color keying fixups */
6008 UINT height
= surface
->resource
.height
;
6010 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6011 dst_pitch
= width
* format
.conv_byte_count
;
6012 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
6014 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
6016 ERR("Out of memory (%u).\n", dst_pitch
* height
);
6017 context_release(context
);
6018 return E_OUTOFMEMORY
;
6020 d3dfmt_convert_surface(surface
->resource
.allocatedMemory
, mem
, src_pitch
,
6021 width
, height
, dst_pitch
, convert
, surface
);
6025 mem
= surface
->resource
.allocatedMemory
;
6028 data
.buffer_object
= surface
->flags
& SFLAG_PBO
? surface
->pbo
: 0;
6030 surface_upload_data(surface
, gl_info
, &format
, &src_rect
, width
, &dst_point
, srgb
, &data
);
6032 context_release(context
);
6034 /* Don't delete PBO memory. */
6035 if ((mem
!= surface
->resource
.allocatedMemory
) && !(surface
->flags
& SFLAG_PBO
))
6036 HeapFree(GetProcessHeap(), 0, mem
);
6041 static void surface_multisample_resolve(struct wined3d_surface
*surface
)
6043 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
6045 if (!(surface
->flags
& SFLAG_INRB_MULTISAMPLE
))
6046 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface
);
6048 surface_blt_fbo(surface
->resource
.device
, WINED3DTEXF_POINT
,
6049 surface
, SFLAG_INRB_MULTISAMPLE
, &rect
, surface
, SFLAG_INRB_RESOLVED
, &rect
);
6052 HRESULT
surface_load_location(struct wined3d_surface
*surface
, DWORD location
, const RECT
*rect
)
6054 struct wined3d_device
*device
= surface
->resource
.device
;
6055 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6058 TRACE("surface %p, location %s, rect %s.\n", surface
, debug_surflocation(location
), wine_dbgstr_rect(rect
));
6060 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
6062 if (location
== SFLAG_INTEXTURE
)
6064 struct wined3d_context
*context
= context_acquire(device
, NULL
);
6065 surface_load_ds_location(surface
, context
, SFLAG_DS_OFFSCREEN
);
6066 context_release(context
);
6071 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location
));
6072 return WINED3DERR_INVALIDCALL
;
6076 if (location
== SFLAG_INSRGBTEX
&& gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
6077 location
= SFLAG_INTEXTURE
;
6079 if (surface
->flags
& location
)
6081 TRACE("Location already up to date.\n");
6085 if (WARN_ON(d3d_surface
))
6087 DWORD required_access
= resource_access_from_location(location
);
6088 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
6089 WARN("Operation requires %#x access, but surface only has %#x.\n",
6090 required_access
, surface
->resource
.access_flags
);
6093 if (!(surface
->flags
& SFLAG_LOCATIONS
))
6095 ERR("Surface %p does not have any up to date location.\n", surface
);
6096 surface
->flags
|= SFLAG_LOST
;
6097 return WINED3DERR_DEVICELOST
;
6102 case SFLAG_INSYSMEM
:
6103 surface_load_sysmem(surface
, gl_info
, rect
);
6106 case SFLAG_INDRAWABLE
:
6107 if (FAILED(hr
= surface_load_drawable(surface
, gl_info
, rect
)))
6111 case SFLAG_INRB_RESOLVED
:
6112 surface_multisample_resolve(surface
);
6115 case SFLAG_INTEXTURE
:
6116 case SFLAG_INSRGBTEX
:
6117 if (FAILED(hr
= surface_load_texture(surface
, gl_info
, rect
, location
== SFLAG_INSRGBTEX
)))
6122 ERR("Don't know how to handle location %#x.\n", location
);
6128 surface
->flags
|= location
;
6130 if (location
!= SFLAG_INSYSMEM
&& (surface
->flags
& SFLAG_INSYSMEM
))
6131 surface_evict_sysmem(surface
);
6134 if (surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)
6135 && gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
6137 surface
->flags
|= (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
);
6143 BOOL
surface_is_offscreen(const struct wined3d_surface
*surface
)
6145 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
6147 /* Not on a swapchain - must be offscreen */
6148 if (surface
->container
.type
!= WINED3D_CONTAINER_SWAPCHAIN
) return TRUE
;
6150 /* The front buffer is always onscreen */
6151 if (surface
== swapchain
->front_buffer
) return FALSE
;
6153 /* If the swapchain is rendered to an FBO, the backbuffer is
6154 * offscreen, otherwise onscreen */
6155 return swapchain
->render_to_fbo
;
6158 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
6159 /* Context activation is done by the caller. */
6160 static void ffp_blit_free(struct wined3d_device
*device
) { }
6162 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6163 /* Context activation is done by the caller. */
6164 static void ffp_blit_p8_upload_palette(const struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
6167 BOOL colorkey_active
= (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
) ? TRUE
: FALSE
;
6169 d3dfmt_p8_init_palette(surface
, table
, colorkey_active
);
6171 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6173 GL_EXTCALL(glColorTableEXT(surface
->texture_target
, GL_RGBA
, 256, GL_RGBA
, GL_UNSIGNED_BYTE
, table
));
6177 /* Context activation is done by the caller. */
6178 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, struct wined3d_surface
*surface
)
6180 enum complex_fixup fixup
= get_complex_fixup(surface
->resource
.format
->color_fixup
);
6182 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6183 * else the surface is converted in software at upload time in LoadLocation.
6185 if(fixup
== COMPLEX_FIXUP_P8
&& context
->gl_info
->supported
[EXT_PALETTED_TEXTURE
])
6186 ffp_blit_p8_upload_palette(surface
, context
->gl_info
);
6189 glEnable(surface
->texture_target
);
6190 checkGLcall("glEnable(surface->texture_target)");
6195 /* Context activation is done by the caller. */
6196 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
6199 glDisable(GL_TEXTURE_2D
);
6200 checkGLcall("glDisable(GL_TEXTURE_2D)");
6201 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
6203 glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
6204 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6206 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
6208 glDisable(GL_TEXTURE_RECTANGLE_ARB
);
6209 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6214 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
6215 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
6216 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
6218 enum complex_fixup src_fixup
;
6222 case WINED3D_BLIT_OP_COLOR_BLIT
:
6223 if (src_pool
== WINED3DPOOL_SYSTEMMEM
|| dst_pool
== WINED3DPOOL_SYSTEMMEM
)
6226 src_fixup
= get_complex_fixup(src_format
->color_fixup
);
6227 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
6229 TRACE("Checking support for fixup:\n");
6230 dump_color_fixup_desc(src_format
->color_fixup
);
6233 if (!is_identity_fixup(dst_format
->color_fixup
))
6235 TRACE("Destination fixups are not supported\n");
6239 if (src_fixup
== COMPLEX_FIXUP_P8
&& gl_info
->supported
[EXT_PALETTED_TEXTURE
])
6241 TRACE("P8 fixup supported\n");
6245 /* We only support identity conversions. */
6246 if (is_identity_fixup(src_format
->color_fixup
))
6252 TRACE("[FAILED]\n");
6255 case WINED3D_BLIT_OP_COLOR_FILL
:
6256 if (dst_pool
== WINED3DPOOL_SYSTEMMEM
)
6259 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6261 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
6264 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
6266 TRACE("Color fill not supported\n");
6270 /* FIXME: We should reject color fills on formats with fixups,
6271 * but this would break P8 color fills for example. */
6275 case WINED3D_BLIT_OP_DEPTH_FILL
:
6279 TRACE("Unsupported blit_op=%d\n", blit_op
);
6284 /* Do not call while under the GL lock. */
6285 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
6286 const RECT
*dst_rect
, const WINED3DCOLORVALUE
*color
)
6288 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
6289 struct wined3d_fb_state fb
= {&dst_surface
, NULL
};
6291 return device_clear_render_targets(device
, 1, &fb
,
6292 1, dst_rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
6295 /* Do not call while under the GL lock. */
6296 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
,
6297 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
6299 const RECT draw_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
6300 struct wined3d_fb_state fb
= {NULL
, surface
};
6302 return device_clear_render_targets(device
, 0, &fb
,
6303 1, rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
6306 const struct blit_shader ffp_blit
= {
6312 ffp_blit_color_fill
,
6313 ffp_blit_depth_fill
,
6316 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
6321 /* Context activation is done by the caller. */
6322 static void cpu_blit_free(struct wined3d_device
*device
)
6326 /* Context activation is done by the caller. */
6327 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, struct wined3d_surface
*surface
)
6332 /* Context activation is done by the caller. */
6333 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
6337 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
6338 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
6339 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
6341 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
6349 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
6350 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
6351 const WINEDDBLTFX
*fx
, WINED3DTEXTUREFILTERTYPE filter
)
6353 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
6354 const struct wined3d_format
*src_format
, *dst_format
;
6355 struct wined3d_surface
*orig_src
= src_surface
;
6356 WINED3DLOCKED_RECT dlock
, slock
;
6357 HRESULT hr
= WINED3D_OK
;
6363 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6364 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
6365 flags
, fx
, debug_d3dtexturefiltertype(filter
));
6375 full_rect
.right
= dst_surface
->resource
.width
;
6376 full_rect
.bottom
= dst_surface
->resource
.height
;
6377 IntersectRect(&xdst
, &full_rect
, dst_rect
);
6381 BOOL clip_horiz
, clip_vert
;
6384 clip_horiz
= xdst
.left
< 0 || xdst
.right
> (int)dst_surface
->resource
.width
;
6385 clip_vert
= xdst
.top
< 0 || xdst
.bottom
> (int)dst_surface
->resource
.height
;
6387 if (clip_vert
|| clip_horiz
)
6389 /* Now check if this is a special case or not... */
6390 if ((flags
& WINEDDBLT_DDFX
)
6391 || (clip_horiz
&& xdst
.right
- xdst
.left
!= xsrc
.right
- xsrc
.left
)
6392 || (clip_vert
&& xdst
.bottom
- xdst
.top
!= xsrc
.bottom
- xsrc
.top
))
6394 WARN("Out of screen rectangle in special case. Not handled right now.\n");
6402 xsrc
.left
-= xdst
.left
;
6405 if (xdst
.right
> dst_surface
->resource
.width
)
6407 xsrc
.right
-= (xdst
.right
- (int)dst_surface
->resource
.width
);
6408 xdst
.right
= (int)dst_surface
->resource
.width
;
6416 xsrc
.top
-= xdst
.top
;
6419 if (xdst
.bottom
> dst_surface
->resource
.height
)
6421 xsrc
.bottom
-= (xdst
.bottom
- (int)dst_surface
->resource
.height
);
6422 xdst
.bottom
= (int)dst_surface
->resource
.height
;
6426 /* And check if after clipping something is still to be done... */
6427 if ((xdst
.right
<= 0) || (xdst
.bottom
<= 0)
6428 || (xdst
.left
>= (int)dst_surface
->resource
.width
)
6429 || (xdst
.top
>= (int)dst_surface
->resource
.height
)
6430 || (xsrc
.right
<= 0) || (xsrc
.bottom
<= 0)
6431 || (xsrc
.left
>= (int)src_surface
->resource
.width
)
6432 || (xsrc
.top
>= (int)src_surface
->resource
.height
))
6434 TRACE("Nothing to be done after clipping.\n");
6440 if (src_surface
== dst_surface
)
6442 wined3d_surface_map(dst_surface
, &dlock
, NULL
, 0);
6444 src_format
= dst_surface
->resource
.format
;
6445 dst_format
= src_format
;
6449 dst_format
= dst_surface
->resource
.format
;
6452 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
6454 src_surface
= surface_convert_format(src_surface
, dst_format
->id
);
6457 /* The conv function writes a FIXME */
6458 WARN("Cannot convert source surface format to dest format.\n");
6462 wined3d_surface_map(src_surface
, &slock
, NULL
, WINED3DLOCK_READONLY
);
6463 src_format
= src_surface
->resource
.format
;
6467 src_format
= dst_format
;
6470 wined3d_surface_map(dst_surface
, &dlock
, &xdst
, 0);
6472 wined3d_surface_map(dst_surface
, &dlock
, NULL
, 0);
6475 bpp
= dst_surface
->resource
.format
->byte_count
;
6476 srcheight
= xsrc
.bottom
- xsrc
.top
;
6477 srcwidth
= xsrc
.right
- xsrc
.left
;
6478 dstheight
= xdst
.bottom
- xdst
.top
;
6479 dstwidth
= xdst
.right
- xdst
.left
;
6480 width
= (xdst
.right
- xdst
.left
) * bpp
;
6482 if (src_format
->flags
& dst_format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
6484 UINT row_block_count
;
6486 if (flags
|| src_surface
== dst_surface
)
6488 FIXME("Only plain blits supported on compressed surfaces.\n");
6493 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
6495 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
6497 WARN("Stretching not supported on compressed surfaces.\n");
6498 hr
= WINED3DERR_INVALIDCALL
;
6505 row_block_count
= (dstwidth
+ dst_format
->block_width
- 1) / dst_format
->block_width
;
6506 for (y
= 0; y
< dstheight
; y
+= dst_format
->block_height
)
6508 memcpy(dbuf
, sbuf
, row_block_count
* dst_format
->block_byte_count
);
6509 dbuf
+= dlock
.Pitch
;
6510 sbuf
+= slock
.Pitch
;
6516 if (dst_rect
&& src_surface
!= dst_surface
)
6519 dbuf
= (BYTE
*)dlock
.pBits
+(xdst
.top
*dlock
.Pitch
)+(xdst
.left
*bpp
);
6521 /* First, all the 'source-less' blits */
6522 if (flags
& WINEDDBLT_COLORFILL
)
6524 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dlock
.Pitch
, fx
->u5
.dwFillColor
);
6525 flags
&= ~WINEDDBLT_COLORFILL
;
6528 if (flags
& WINEDDBLT_DEPTHFILL
)
6530 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6532 if (flags
& WINEDDBLT_ROP
)
6534 /* Catch some degenerate cases here. */
6538 hr
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,0);
6540 case 0xAA0029: /* No-op */
6543 hr
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,~0);
6545 case SRCCOPY
: /* Well, we do that below? */
6548 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx
->dwROP
, fx
->u5
.lpDDSPattern
);
6551 flags
&= ~WINEDDBLT_ROP
;
6553 if (flags
& WINEDDBLT_DDROPS
)
6555 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx
->dwDDROP
, fx
->u5
.lpDDSPattern
);
6557 /* Now the 'with source' blits. */
6561 int sx
, xinc
, sy
, yinc
;
6563 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
6566 if (filter
!= WINED3DTEXF_NONE
&& filter
!= WINED3DTEXF_POINT
6567 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
6569 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6570 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
6573 sbase
= (BYTE
*)slock
.pBits
+(xsrc
.top
*slock
.Pitch
)+xsrc
.left
*bpp
;
6574 xinc
= (srcwidth
<< 16) / dstwidth
;
6575 yinc
= (srcheight
<< 16) / dstheight
;
6579 /* No effects, we can cheat here. */
6580 if (dstwidth
== srcwidth
)
6582 if (dstheight
== srcheight
)
6584 /* No stretching in either direction. This needs to be as
6585 * fast as possible. */
6588 /* Check for overlapping surfaces. */
6589 if (src_surface
!= dst_surface
|| xdst
.top
< xsrc
.top
6590 || xdst
.right
<= xsrc
.left
|| xsrc
.right
<= xdst
.left
)
6592 /* No overlap, or dst above src, so copy from top downwards. */
6593 for (y
= 0; y
< dstheight
; ++y
)
6595 memcpy(dbuf
, sbuf
, width
);
6596 sbuf
+= slock
.Pitch
;
6597 dbuf
+= dlock
.Pitch
;
6600 else if (xdst
.top
> xsrc
.top
)
6602 /* Copy from bottom upwards. */
6603 sbuf
+= (slock
.Pitch
*dstheight
);
6604 dbuf
+= (dlock
.Pitch
*dstheight
);
6605 for (y
= 0; y
< dstheight
; ++y
)
6607 sbuf
-= slock
.Pitch
;
6608 dbuf
-= dlock
.Pitch
;
6609 memcpy(dbuf
, sbuf
, width
);
6614 /* Src and dst overlapping on the same line, use memmove. */
6615 for (y
= 0; y
< dstheight
; ++y
)
6617 memmove(dbuf
, sbuf
, width
);
6618 sbuf
+= slock
.Pitch
;
6619 dbuf
+= dlock
.Pitch
;
6625 /* Stretching in y direction only. */
6626 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6628 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
6629 memcpy(dbuf
, sbuf
, width
);
6630 dbuf
+= dlock
.Pitch
;
6636 /* Stretching in X direction. */
6638 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6640 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
6642 if ((sy
>> 16) == (last_sy
>> 16))
6644 /* This source row is the same as last source row -
6645 * Copy the already stretched row. */
6646 memcpy(dbuf
, dbuf
- dlock
.Pitch
, width
);
6650 #define STRETCH_ROW(type) \
6652 const type *s = (const type *)sbuf; \
6653 type *d = (type *)dbuf; \
6654 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6655 d[x] = s[sx >> 16]; \
6673 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
6677 s
= sbuf
+ 3 * (sx
>> 16);
6678 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
6679 d
[0] = (pixel
) & 0xff;
6680 d
[1] = (pixel
>> 8) & 0xff;
6681 d
[2] = (pixel
>> 16) & 0xff;
6687 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
6688 hr
= WINED3DERR_NOTAVAILABLE
;
6693 dbuf
+= dlock
.Pitch
;
6700 LONG dstyinc
= dlock
.Pitch
, dstxinc
= bpp
;
6701 DWORD keylow
= 0xFFFFFFFF, keyhigh
= 0, keymask
= 0xFFFFFFFF;
6702 DWORD destkeylow
= 0x0, destkeyhigh
= 0xFFFFFFFF, destkeymask
= 0xFFFFFFFF;
6703 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
6705 /* The color keying flags are checked for correctness in ddraw */
6706 if (flags
& WINEDDBLT_KEYSRC
)
6708 keylow
= src_surface
->SrcBltCKey
.dwColorSpaceLowValue
;
6709 keyhigh
= src_surface
->SrcBltCKey
.dwColorSpaceHighValue
;
6711 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
6713 keylow
= fx
->ddckSrcColorkey
.dwColorSpaceLowValue
;
6714 keyhigh
= fx
->ddckSrcColorkey
.dwColorSpaceHighValue
;
6717 if (flags
& WINEDDBLT_KEYDEST
)
6719 /* Destination color keys are taken from the source surface! */
6720 destkeylow
= src_surface
->DestBltCKey
.dwColorSpaceLowValue
;
6721 destkeyhigh
= src_surface
->DestBltCKey
.dwColorSpaceHighValue
;
6723 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
6725 destkeylow
= fx
->ddckDestColorkey
.dwColorSpaceLowValue
;
6726 destkeyhigh
= fx
->ddckDestColorkey
.dwColorSpaceHighValue
;
6735 keymask
= src_format
->red_mask
6736 | src_format
->green_mask
6737 | src_format
->blue_mask
;
6739 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
6742 if (flags
& WINEDDBLT_DDFX
)
6744 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
6747 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
6748 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dlock
.Pitch
);
6749 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
6751 if (fx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
6753 /* I don't think we need to do anything about this flag */
6754 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
6756 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
6759 dTopRight
= dTopLeft
;
6762 dBottomRight
= dBottomLeft
;
6764 dstxinc
= dstxinc
* -1;
6766 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
6769 dTopLeft
= dBottomLeft
;
6772 dTopRight
= dBottomRight
;
6774 dstyinc
= dstyinc
* -1;
6776 if (fx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
6778 /* I don't think we need to do anything about this flag */
6779 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
6781 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
6784 dBottomRight
= dTopLeft
;
6787 dBottomLeft
= dTopRight
;
6789 dstxinc
= dstxinc
* -1;
6790 dstyinc
= dstyinc
* -1;
6792 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
6795 dTopLeft
= dBottomLeft
;
6796 dBottomLeft
= dBottomRight
;
6797 dBottomRight
= dTopRight
;
6802 dstxinc
= dstxinc
* -1;
6804 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
6807 dTopLeft
= dTopRight
;
6808 dTopRight
= dBottomRight
;
6809 dBottomRight
= dBottomLeft
;
6814 dstyinc
= dstyinc
* -1;
6816 if (fx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
6818 /* I don't think we need to do anything about this flag */
6819 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
6822 flags
&= ~(WINEDDBLT_DDFX
);
6825 #define COPY_COLORKEY_FX(type) \
6828 type *d = (type *)dbuf, *dx, tmp; \
6829 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
6831 s = (const type *)(sbase + (sy >> 16) * slock.Pitch); \
6833 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6835 tmp = s[sx >> 16]; \
6836 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
6837 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
6841 dx = (type *)(((BYTE *)dx) + dstxinc); \
6843 d = (type *)(((BYTE *)d) + dstyinc); \
6850 COPY_COLORKEY_FX(BYTE
);
6853 COPY_COLORKEY_FX(WORD
);
6856 COPY_COLORKEY_FX(DWORD
);
6861 BYTE
*d
= dbuf
, *dx
;
6862 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6864 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
6866 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
6868 DWORD pixel
, dpixel
= 0;
6869 s
= sbuf
+ 3 * (sx
>>16);
6870 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
6871 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
6872 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
6873 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
6875 dx
[0] = (pixel
) & 0xff;
6876 dx
[1] = (pixel
>> 8) & 0xff;
6877 dx
[2] = (pixel
>> 16) & 0xff;
6886 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
6887 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
* 8);
6888 hr
= WINED3DERR_NOTAVAILABLE
;
6890 #undef COPY_COLORKEY_FX
6896 if (flags
&& FIXME_ON(d3d_surface
))
6898 FIXME("\tUnsupported flags: %#x.\n", flags
);
6902 wined3d_surface_unmap(dst_surface
);
6903 if (src_surface
&& src_surface
!= dst_surface
)
6904 wined3d_surface_unmap(src_surface
);
6905 /* Release the converted surface, if any. */
6906 if (src_surface
&& src_surface
!= orig_src
)
6907 wined3d_surface_decref(src_surface
);
6912 /* Do not call while under the GL lock. */
6913 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
6914 const RECT
*dst_rect
, const WINED3DCOLORVALUE
*color
)
6916 static const RECT src_rect
;
6919 memset(&BltFx
, 0, sizeof(BltFx
));
6920 BltFx
.dwSize
= sizeof(BltFx
);
6921 BltFx
.u5
.dwFillColor
= wined3d_format_convert_from_float(dst_surface
, color
);
6922 return surface_cpu_blt(dst_surface
, dst_rect
, NULL
, &src_rect
,
6923 WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
6926 /* Do not call while under the GL lock. */
6927 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
6928 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
6930 FIXME("Depth filling not implemented by cpu_blit.\n");
6931 return WINED3DERR_INVALIDCALL
;
6934 const struct blit_shader cpu_blit
= {
6940 cpu_blit_color_fill
,
6941 cpu_blit_depth_fill
,
6944 static HRESULT
surface_init(struct wined3d_surface
*surface
, WINED3DSURFTYPE surface_type
, UINT alignment
,
6945 UINT width
, UINT height
, UINT level
, BOOL lockable
, BOOL discard
, WINED3DMULTISAMPLE_TYPE multisample_type
,
6946 UINT multisample_quality
, struct wined3d_device
*device
, DWORD usage
, enum wined3d_format_id format_id
,
6947 WINED3DPOOL pool
, void *parent
, const struct wined3d_parent_ops
*parent_ops
)
6949 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6950 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
6951 unsigned int resource_size
;
6954 if (multisample_quality
> 0)
6956 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality
);
6957 multisample_quality
= 0;
6960 /* Quick lockable sanity check.
6961 * TODO: remove this after surfaces, usage and lockability have been debugged properly
6962 * this function is too deep to need to care about things like this.
6963 * Levels need to be checked too, since they all affect what can be done. */
6966 case WINED3DPOOL_SCRATCH
:
6969 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
6970 "which are mutually exclusive, setting lockable to TRUE.\n");
6975 case WINED3DPOOL_SYSTEMMEM
:
6977 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
6980 case WINED3DPOOL_MANAGED
:
6981 if (usage
& WINED3DUSAGE_DYNAMIC
)
6982 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
6985 case WINED3DPOOL_DEFAULT
:
6986 if (lockable
&& !(usage
& (WINED3DUSAGE_DYNAMIC
| WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
6987 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
6991 FIXME("Unknown pool %#x.\n", pool
);
6995 if (usage
& WINED3DUSAGE_RENDERTARGET
&& pool
!= WINED3DPOOL_DEFAULT
)
6996 FIXME("Trying to create a render target that isn't in the default pool.\n");
6998 /* FIXME: Check that the format is supported by the device. */
7000 resource_size
= wined3d_format_calculate_size(format
, alignment
, width
, height
);
7002 return WINED3DERR_INVALIDCALL
;
7004 surface
->surface_type
= surface_type
;
7006 switch (surface_type
)
7008 case SURFACE_OPENGL
:
7009 surface
->surface_ops
= &surface_ops
;
7013 surface
->surface_ops
= &gdi_surface_ops
;
7017 ERR("Requested unknown surface implementation %#x.\n", surface_type
);
7018 return WINED3DERR_INVALIDCALL
;
7021 hr
= resource_init(&surface
->resource
, device
, WINED3DRTYPE_SURFACE
, format
,
7022 multisample_type
, multisample_quality
, usage
, pool
, width
, height
, 1,
7023 resource_size
, parent
, parent_ops
, &surface_resource_ops
);
7026 WARN("Failed to initialize resource, returning %#x.\n", hr
);
7030 /* "Standalone" surface. */
7031 surface_set_container(surface
, WINED3D_CONTAINER_NONE
, NULL
);
7033 surface
->texture_level
= level
;
7034 list_init(&surface
->overlays
);
7037 surface
->flags
= SFLAG_NORMCOORD
; /* Default to normalized coords. */
7039 surface
->flags
|= SFLAG_DISCARD
;
7040 if (lockable
|| format_id
== WINED3DFMT_D16_LOCKABLE
)
7041 surface
->flags
|= SFLAG_LOCKABLE
;
7042 /* I'm not sure if this qualifies as a hack or as an optimization. It
7043 * seems reasonable to assume that lockable render targets will get
7044 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7045 * creation. However, the other reason we want to do this is that several
7046 * ddraw applications access surface memory while the surface isn't
7047 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7048 * future locks prevents these from crashing. */
7049 if (lockable
&& (usage
& WINED3DUSAGE_RENDERTARGET
))
7050 surface
->flags
|= SFLAG_DYNLOCK
;
7052 /* Mark the texture as dirty so that it gets loaded first time around. */
7053 surface_add_dirty_rect(surface
, NULL
);
7054 list_init(&surface
->renderbuffers
);
7056 TRACE("surface %p, memory %p, size %u\n",
7057 surface
, surface
->resource
.allocatedMemory
, surface
->resource
.size
);
7059 /* Call the private setup routine */
7060 hr
= surface
->surface_ops
->surface_private_setup(surface
);
7063 ERR("Private setup failed, returning %#x\n", hr
);
7064 surface
->surface_ops
->surface_cleanup(surface
);
7071 HRESULT CDECL
wined3d_surface_create(struct wined3d_device
*device
, UINT width
, UINT height
,
7072 enum wined3d_format_id format_id
, BOOL lockable
, BOOL discard
, UINT level
, DWORD usage
, WINED3DPOOL pool
,
7073 WINED3DMULTISAMPLE_TYPE multisample_type
, DWORD multisample_quality
, WINED3DSURFTYPE surface_type
,
7074 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_surface
**surface
)
7076 struct wined3d_surface
*object
;
7079 TRACE("device %p, width %u, height %u, format %s, lockable %#x, discard %#x, level %u\n",
7080 device
, width
, height
, debug_d3dformat(format_id
), lockable
, discard
, level
);
7081 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7082 surface
, debug_d3dusage(usage
), usage
, debug_d3dpool(pool
), multisample_type
, multisample_quality
);
7083 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", surface_type
, parent
, parent_ops
);
7085 if (surface_type
== SURFACE_OPENGL
&& !device
->adapter
)
7087 ERR("OpenGL surfaces are not available without OpenGL.\n");
7088 return WINED3DERR_NOTAVAILABLE
;
7091 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
7094 ERR("Failed to allocate surface memory.\n");
7095 return WINED3DERR_OUTOFVIDEOMEMORY
;
7098 hr
= surface_init(object
, surface_type
, device
->surface_alignment
, width
, height
, level
, lockable
,
7099 discard
, multisample_type
, multisample_quality
, device
, usage
, format_id
, pool
, parent
, parent_ops
);
7102 WARN("Failed to initialize surface, returning %#x.\n", hr
);
7103 HeapFree(GetProcessHeap(), 0, object
);
7107 TRACE("Created surface %p.\n", object
);