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
) || !list_empty(&surface
->renderbuffers
))
49 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
50 const struct wined3d_gl_info
*gl_info
;
51 struct wined3d_context
*context
;
53 context
= context_acquire(surface
->resource
.device
, NULL
);
54 gl_info
= context
->gl_info
;
58 if (surface
->texture_name
)
60 TRACE("Deleting texture %u.\n", surface
->texture_name
);
61 glDeleteTextures(1, &surface
->texture_name
);
64 if (surface
->flags
& SFLAG_PBO
)
66 TRACE("Deleting PBO %u.\n", surface
->pbo
);
67 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
70 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
72 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
73 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
74 HeapFree(GetProcessHeap(), 0, entry
);
79 context_release(context
);
82 if (surface
->flags
& SFLAG_DIBSECTION
)
85 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
86 DeleteDC(surface
->hDC
);
87 /* Release the DIB section. */
88 DeleteObject(surface
->dib
.DIBsection
);
89 surface
->dib
.bitmap_data
= NULL
;
90 surface
->resource
.allocatedMemory
= NULL
;
93 if (surface
->flags
& SFLAG_USERPTR
)
94 wined3d_surface_set_mem(surface
, NULL
);
95 if (surface
->overlay_dest
)
96 list_remove(&surface
->overlay_entry
);
98 HeapFree(GetProcessHeap(), 0, surface
->palette9
);
100 resource_cleanup(&surface
->resource
);
103 void surface_set_container(struct wined3d_surface
*surface
, enum wined3d_container_type type
, void *container
)
105 TRACE("surface %p, container %p.\n", surface
, container
);
107 if (!container
&& type
!= WINED3D_CONTAINER_NONE
)
108 ERR("Setting NULL container of type %#x.\n", type
);
110 if (type
== WINED3D_CONTAINER_SWAPCHAIN
)
112 surface
->get_drawable_size
= get_drawable_size_swapchain
;
116 switch (wined3d_settings
.offscreen_rendering_mode
)
119 surface
->get_drawable_size
= get_drawable_size_fbo
;
123 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
127 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
132 surface
->container
.type
= type
;
133 surface
->container
.u
.base
= container
;
140 enum tex_types tex_type
;
141 GLfloat coords
[4][3];
152 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
154 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
155 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
156 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
157 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
160 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
162 GLfloat (*coords
)[3] = info
->coords
;
168 FIXME("Unsupported texture target %#x\n", target
);
169 /* Fall back to GL_TEXTURE_2D */
171 info
->binding
= GL_TEXTURE_BINDING_2D
;
172 info
->bind_target
= GL_TEXTURE_2D
;
173 info
->tex_type
= tex_2d
;
174 coords
[0][0] = (float)rect
->left
/ w
;
175 coords
[0][1] = (float)rect
->top
/ h
;
178 coords
[1][0] = (float)rect
->right
/ w
;
179 coords
[1][1] = (float)rect
->top
/ h
;
182 coords
[2][0] = (float)rect
->left
/ w
;
183 coords
[2][1] = (float)rect
->bottom
/ h
;
186 coords
[3][0] = (float)rect
->right
/ w
;
187 coords
[3][1] = (float)rect
->bottom
/ h
;
191 case GL_TEXTURE_RECTANGLE_ARB
:
192 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
193 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
194 info
->tex_type
= tex_rect
;
195 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
196 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
197 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
198 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
201 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
202 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
203 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
204 info
->tex_type
= tex_cube
;
205 cube_coords_float(rect
, w
, h
, &f
);
207 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
208 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
209 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
210 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
213 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
214 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
215 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
216 info
->tex_type
= tex_cube
;
217 cube_coords_float(rect
, w
, h
, &f
);
219 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
220 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
221 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
222 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
225 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
226 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
227 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
228 info
->tex_type
= tex_cube
;
229 cube_coords_float(rect
, w
, h
, &f
);
231 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
232 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
233 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
234 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
237 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
238 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
239 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
240 info
->tex_type
= tex_cube
;
241 cube_coords_float(rect
, w
, h
, &f
);
243 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
244 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
245 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
246 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
249 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
250 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
251 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
252 info
->tex_type
= tex_cube
;
253 cube_coords_float(rect
, w
, h
, &f
);
255 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
256 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
257 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
258 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
261 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
262 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
263 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
264 info
->tex_type
= tex_cube
;
265 cube_coords_float(rect
, w
, h
, &f
);
267 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
268 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
269 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
270 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
275 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
278 *rect_out
= *rect_in
;
283 rect_out
->right
= surface
->resource
.width
;
284 rect_out
->bottom
= surface
->resource
.height
;
288 /* GL locking and context activation is done by the caller */
289 void draw_textured_quad(const struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
290 const RECT
*dst_rect
, WINED3DTEXTUREFILTERTYPE Filter
)
292 struct blt_info info
;
294 surface_get_blt_info(src_surface
->texture_target
, src_rect
, src_surface
->pow2Width
, src_surface
->pow2Height
, &info
);
296 glEnable(info
.bind_target
);
297 checkGLcall("glEnable(bind_target)");
299 /* Bind the texture */
300 glBindTexture(info
.bind_target
, src_surface
->texture_name
);
301 checkGLcall("glBindTexture");
303 /* Filtering for StretchRect */
304 glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
,
305 wined3d_gl_mag_filter(magLookup
, Filter
));
306 checkGLcall("glTexParameteri");
307 glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
308 wined3d_gl_min_mip_filter(minMipLookup
, Filter
, WINED3DTEXF_NONE
));
309 checkGLcall("glTexParameteri");
310 glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
311 glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
312 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
313 checkGLcall("glTexEnvi");
316 glBegin(GL_TRIANGLE_STRIP
);
317 glTexCoord3fv(info
.coords
[0]);
318 glVertex2i(dst_rect
->left
, dst_rect
->top
);
320 glTexCoord3fv(info
.coords
[1]);
321 glVertex2i(dst_rect
->right
, dst_rect
->top
);
323 glTexCoord3fv(info
.coords
[2]);
324 glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
326 glTexCoord3fv(info
.coords
[3]);
327 glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
330 /* Unbind the texture */
331 glBindTexture(info
.bind_target
, 0);
332 checkGLcall("glBindTexture(info->bind_target, 0)");
334 /* We changed the filtering settings on the texture. Inform the
335 * container about this to get the filters reset properly next draw. */
336 if (src_surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
338 struct wined3d_texture
*texture
= src_surface
->container
.u
.texture
;
339 texture
->texture_rgb
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
340 texture
->texture_rgb
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
341 texture
->texture_rgb
.states
[WINED3DTEXSTA_MIPFILTER
] = WINED3DTEXF_NONE
;
345 static HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
347 const struct wined3d_format
*format
= surface
->resource
.format
;
355 TRACE("surface %p.\n", surface
);
357 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
359 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
360 return WINED3DERR_INVALIDCALL
;
363 switch (format
->byte_count
)
367 /* Allocate extra space to store the RGB bit masks. */
368 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
372 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
376 /* Allocate extra space for a palette. */
377 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
378 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
383 return E_OUTOFMEMORY
;
385 /* Some applications access the surface in via DWORDs, and do not take
386 * the necessary care at the end of the surface. So we need at least
387 * 4 extra bytes at the end of the surface. Check against the page size,
388 * if the last page used for the surface has at least 4 spare bytes we're
389 * safe, otherwise add an extra line to the DIB section. */
390 GetSystemInfo(&sysInfo
);
391 if( ((surface
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4)
394 TRACE("Adding an extra line to the DIB section.\n");
397 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
398 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
399 b_info
->bmiHeader
.biWidth
= wined3d_surface_get_pitch(surface
) / format
->byte_count
;
400 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
- extraline
;
401 b_info
->bmiHeader
.biSizeImage
= (surface
->resource
.height
+ extraline
)
402 * wined3d_surface_get_pitch(surface
);
403 b_info
->bmiHeader
.biPlanes
= 1;
404 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
406 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
407 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
408 b_info
->bmiHeader
.biClrUsed
= 0;
409 b_info
->bmiHeader
.biClrImportant
= 0;
411 /* Get the bit masks */
412 masks
= (DWORD
*)b_info
->bmiColors
;
413 switch (surface
->resource
.format
->id
)
415 case WINED3DFMT_B8G8R8_UNORM
:
416 usage
= DIB_RGB_COLORS
;
417 b_info
->bmiHeader
.biCompression
= BI_RGB
;
420 case WINED3DFMT_B5G5R5X1_UNORM
:
421 case WINED3DFMT_B5G5R5A1_UNORM
:
422 case WINED3DFMT_B4G4R4A4_UNORM
:
423 case WINED3DFMT_B4G4R4X4_UNORM
:
424 case WINED3DFMT_B2G3R3_UNORM
:
425 case WINED3DFMT_B2G3R3A8_UNORM
:
426 case WINED3DFMT_R10G10B10A2_UNORM
:
427 case WINED3DFMT_R8G8B8A8_UNORM
:
428 case WINED3DFMT_R8G8B8X8_UNORM
:
429 case WINED3DFMT_B10G10R10A2_UNORM
:
430 case WINED3DFMT_B5G6R5_UNORM
:
431 case WINED3DFMT_R16G16B16A16_UNORM
:
433 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
434 masks
[0] = format
->red_mask
;
435 masks
[1] = format
->green_mask
;
436 masks
[2] = format
->blue_mask
;
440 /* Don't know palette */
441 b_info
->bmiHeader
.biCompression
= BI_RGB
;
446 if (!(dc
= GetDC(0)))
448 HeapFree(GetProcessHeap(), 0, b_info
);
449 return HRESULT_FROM_WIN32(GetLastError());
452 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
453 b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
,
454 b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
455 surface
->dib
.DIBsection
= CreateDIBSection(dc
, b_info
, usage
, &surface
->dib
.bitmap_data
, 0, 0);
458 if (!surface
->dib
.DIBsection
)
460 ERR("Failed to create DIB section.\n");
461 HeapFree(GetProcessHeap(), 0, b_info
);
462 return HRESULT_FROM_WIN32(GetLastError());
465 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
466 /* Copy the existing surface to the dib section. */
467 if (surface
->resource
.allocatedMemory
)
469 memcpy(surface
->dib
.bitmap_data
, surface
->resource
.allocatedMemory
,
470 surface
->resource
.height
* wined3d_surface_get_pitch(surface
));
474 /* This is to make maps read the GL texture although memory is allocated. */
475 surface
->flags
&= ~SFLAG_INSYSMEM
;
477 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
479 HeapFree(GetProcessHeap(), 0, b_info
);
481 /* Now allocate a DC. */
482 surface
->hDC
= CreateCompatibleDC(0);
483 surface
->dib
.holdbitmap
= SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
484 TRACE("Using wined3d palette %p.\n", surface
->palette
);
485 SelectPalette(surface
->hDC
, surface
->palette
? surface
->palette
->hpal
: 0, FALSE
);
487 surface
->flags
|= SFLAG_DIBSECTION
;
489 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
490 surface
->resource
.heapMemory
= NULL
;
495 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
497 struct wined3d_device
*device
= surface
->resource
.device
;
498 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
500 TRACE("surface %p.\n", surface
);
502 /* Performance optimization: Count how often a surface is locked, if it is
503 * locked regularly do not throw away the system memory copy. This avoids
504 * the need to download the surface from OpenGL all the time. The surface
505 * is still downloaded if the OpenGL texture is changed. */
506 if (!(surface
->flags
& SFLAG_DYNLOCK
))
508 if (++surface
->lockCount
> MAXLOCKCOUNT
)
510 TRACE("Surface is locked regularly, not freeing the system memory copy any more.\n");
511 surface
->flags
|= SFLAG_DYNLOCK
;
515 /* Create a PBO for dynamically locked surfaces but don't do it for
516 * converted or NPOT surfaces. Also don't create a PBO for systemmem
518 if (gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
] && (surface
->flags
& SFLAG_DYNLOCK
)
519 && !(surface
->flags
& (SFLAG_PBO
| SFLAG_CONVERTED
| SFLAG_NONPOW2
))
520 && (surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
))
522 struct wined3d_context
*context
;
525 context
= context_acquire(device
, NULL
);
528 GL_EXTCALL(glGenBuffersARB(1, &surface
->pbo
));
529 error
= glGetError();
530 if (!surface
->pbo
|| error
!= GL_NO_ERROR
)
531 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error
), error
);
533 TRACE("Binding PBO %u.\n", surface
->pbo
);
535 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
536 checkGLcall("glBindBufferARB");
538 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->resource
.size
+ 4,
539 surface
->resource
.allocatedMemory
, GL_STREAM_DRAW_ARB
));
540 checkGLcall("glBufferDataARB");
542 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
543 checkGLcall("glBindBufferARB");
545 /* We don't need the system memory anymore and we can't even use it for PBOs. */
546 if (!(surface
->flags
& SFLAG_CLIENT
))
548 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
549 surface
->resource
.heapMemory
= NULL
;
551 surface
->resource
.allocatedMemory
= NULL
;
552 surface
->flags
|= SFLAG_PBO
;
554 context_release(context
);
556 else if (!(surface
->resource
.allocatedMemory
|| surface
->flags
& SFLAG_PBO
))
558 /* Whatever surface we have, make sure that there is memory allocated
559 * for the downloaded copy, or a PBO to map. */
560 if (!surface
->resource
.heapMemory
)
561 surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
+ RESOURCE_ALIGNMENT
);
563 surface
->resource
.allocatedMemory
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
564 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
566 if (surface
->flags
& SFLAG_INSYSMEM
)
567 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
571 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
573 if (surface
->flags
& SFLAG_DONOTFREE
)
576 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
577 surface
->resource
.allocatedMemory
= NULL
;
578 surface
->resource
.heapMemory
= NULL
;
579 surface_modify_location(surface
, SFLAG_INSYSMEM
, FALSE
);
582 /* Context activation is done by the caller. */
583 static void surface_bind_and_dirtify(struct wined3d_surface
*surface
,
584 const struct wined3d_gl_info
*gl_info
, BOOL srgb
)
586 struct wined3d_device
*device
= surface
->resource
.device
;
587 DWORD active_sampler
;
588 GLint active_texture
;
590 /* We don't need a specific texture unit, but after binding the texture
591 * the current unit is dirty. Read the unit back instead of switching to
592 * 0, this avoids messing around with the state manager's GL states. The
593 * current texture unit should always be a valid one.
595 * To be more specific, this is tricky because we can implicitly be
596 * called from sampler() in state.c. This means we can't touch anything
597 * other than whatever happens to be the currently active texture, or we
598 * would risk marking already applied sampler states dirty again.
600 * TODO: Track the current active texture per GL context instead of using
604 glGetIntegerv(GL_ACTIVE_TEXTURE
, &active_texture
);
606 active_sampler
= device
->rev_tex_unit_map
[active_texture
- GL_TEXTURE0_ARB
];
608 if (active_sampler
!= WINED3D_UNMAPPED_STAGE
)
609 device_invalidate_state(device
, STATE_SAMPLER(active_sampler
));
610 surface_bind(surface
, gl_info
, srgb
);
613 static void surface_force_reload(struct wined3d_surface
*surface
)
615 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
618 static void surface_release_client_storage(struct wined3d_surface
*surface
)
620 struct wined3d_context
*context
= context_acquire(surface
->resource
.device
, NULL
);
623 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
624 if (surface
->texture_name
)
626 surface_bind_and_dirtify(surface
, context
->gl_info
, FALSE
);
627 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
628 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
630 if (surface
->texture_name_srgb
)
632 surface_bind_and_dirtify(surface
, context
->gl_info
, TRUE
);
633 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
634 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
636 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
639 context_release(context
);
641 surface_modify_location(surface
, SFLAG_INSRGBTEX
, FALSE
);
642 surface_modify_location(surface
, SFLAG_INTEXTURE
, FALSE
);
643 surface_force_reload(surface
);
646 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
648 /* TODO: Check against the maximum texture sizes supported by the video card. */
649 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
650 unsigned int pow2Width
, pow2Height
;
652 TRACE("surface %p.\n", surface
);
654 surface
->texture_name
= 0;
655 surface
->texture_target
= GL_TEXTURE_2D
;
657 /* Non-power2 support */
658 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
660 pow2Width
= surface
->resource
.width
;
661 pow2Height
= surface
->resource
.height
;
665 /* Find the nearest pow2 match */
666 pow2Width
= pow2Height
= 1;
667 while (pow2Width
< surface
->resource
.width
)
669 while (pow2Height
< surface
->resource
.height
)
672 surface
->pow2Width
= pow2Width
;
673 surface
->pow2Height
= pow2Height
;
675 if (pow2Width
> surface
->resource
.width
|| pow2Height
> surface
->resource
.height
)
677 /* TODO: Add support for non power two compressed textures. */
678 if (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
680 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
681 surface
, surface
->resource
.width
, surface
->resource
.height
);
682 return WINED3DERR_NOTAVAILABLE
;
686 if (pow2Width
!= surface
->resource
.width
687 || pow2Height
!= surface
->resource
.height
)
689 surface
->flags
|= SFLAG_NONPOW2
;
692 if ((surface
->pow2Width
> gl_info
->limits
.texture_size
|| surface
->pow2Height
> gl_info
->limits
.texture_size
)
693 && !(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
695 /* One of three options:
696 * 1: Do the same as we do with NPOT and scale the texture, (any
697 * texture ops would require the texture to be scaled which is
699 * 2: Set the texture to the maximum size (bad idea).
700 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
701 * 4: Create the surface, but allow it to be used only for DirectDraw
702 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
703 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
704 * the render target. */
705 if (surface
->resource
.pool
== WINED3DPOOL_DEFAULT
|| surface
->resource
.pool
== WINED3DPOOL_MANAGED
)
707 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
708 return WINED3DERR_NOTAVAILABLE
;
711 /* We should never use this surface in combination with OpenGL! */
712 TRACE("Creating an oversized surface: %ux%u.\n",
713 surface
->pow2Width
, surface
->pow2Height
);
717 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
718 * and EXT_PALETTED_TEXTURE is used in combination with texture
719 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
720 * EXT_PALETTED_TEXTURE doesn't work in combination with
721 * ARB_TEXTURE_RECTANGLE. */
722 if (surface
->flags
& SFLAG_NONPOW2
&& gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
723 && !(surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
724 && gl_info
->supported
[EXT_PALETTED_TEXTURE
]
725 && wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
))
727 surface
->texture_target
= GL_TEXTURE_RECTANGLE_ARB
;
728 surface
->pow2Width
= surface
->resource
.width
;
729 surface
->pow2Height
= surface
->resource
.height
;
730 surface
->flags
&= ~(SFLAG_NONPOW2
| SFLAG_NORMCOORD
);
734 switch (wined3d_settings
.offscreen_rendering_mode
)
737 surface
->get_drawable_size
= get_drawable_size_fbo
;
741 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
745 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
746 return WINED3DERR_INVALIDCALL
;
749 surface
->flags
|= SFLAG_INSYSMEM
;
754 static void surface_realize_palette(struct wined3d_surface
*surface
)
756 struct wined3d_palette
*palette
= surface
->palette
;
758 TRACE("surface %p.\n", surface
);
760 if (!palette
) return;
762 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
763 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
765 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
767 /* Make sure the texture is up to date. This call doesn't do
768 * anything if the texture is already up to date. */
769 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
771 /* We want to force a palette refresh, so mark the drawable as not being up to date */
772 if (!surface_is_offscreen(surface
))
773 surface_modify_location(surface
, SFLAG_INDRAWABLE
, FALSE
);
777 if (!(surface
->flags
& SFLAG_INSYSMEM
))
779 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
780 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
782 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
786 if (surface
->flags
& SFLAG_DIBSECTION
)
791 TRACE("Updating the DC's palette.\n");
793 for (i
= 0; i
< 256; ++i
)
795 col
[i
].rgbRed
= palette
->palents
[i
].peRed
;
796 col
[i
].rgbGreen
= palette
->palents
[i
].peGreen
;
797 col
[i
].rgbBlue
= palette
->palents
[i
].peBlue
;
798 col
[i
].rgbReserved
= 0;
800 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
803 /* Propagate the changes to the drawable when we have a palette. */
804 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
805 surface_load_location(surface
, SFLAG_INDRAWABLE
, NULL
);
808 static HRESULT
surface_draw_overlay(struct wined3d_surface
*surface
)
812 /* If there's no destination surface there is nothing to do. */
813 if (!surface
->overlay_dest
)
816 /* Blt calls ModifyLocation on the dest surface, which in turn calls
817 * DrawOverlay to update the overlay. Prevent an endless recursion. */
818 if (surface
->overlay_dest
->flags
& SFLAG_INOVERLAYDRAW
)
821 surface
->overlay_dest
->flags
|= SFLAG_INOVERLAYDRAW
;
822 hr
= wined3d_surface_blt(surface
->overlay_dest
, &surface
->overlay_destrect
, surface
,
823 &surface
->overlay_srcrect
, WINEDDBLT_WAIT
, NULL
, WINED3DTEXF_LINEAR
);
824 surface
->overlay_dest
->flags
&= ~SFLAG_INOVERLAYDRAW
;
829 static void surface_preload(struct wined3d_surface
*surface
)
831 TRACE("surface %p.\n", surface
);
833 surface_internal_preload(surface
, SRGB_ANY
);
836 static void surface_map(struct wined3d_surface
*surface
, const RECT
*rect
, DWORD flags
)
838 struct wined3d_device
*device
= surface
->resource
.device
;
839 const RECT
*pass_rect
= rect
;
841 TRACE("surface %p, rect %s, flags %#x.\n",
842 surface
, wine_dbgstr_rect(rect
), flags
);
844 if (flags
& WINED3DLOCK_DISCARD
)
846 TRACE("WINED3DLOCK_DISCARD flag passed, marking SYSMEM as up to date.\n");
847 surface_prepare_system_memory(surface
);
848 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
852 /* surface_load_location() does not check if the rectangle specifies
853 * the full surface. Most callers don't need that, so do it here. */
854 if (rect
&& !rect
->top
&& !rect
->left
855 && rect
->right
== surface
->resource
.width
856 && rect
->bottom
== surface
->resource
.height
)
859 if (!(wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
860 && ((surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
861 || surface
== device
->fb
.render_targets
[0])))
862 surface_load_location(surface
, SFLAG_INSYSMEM
, pass_rect
);
865 if (surface
->flags
& SFLAG_PBO
)
867 const struct wined3d_gl_info
*gl_info
;
868 struct wined3d_context
*context
;
870 context
= context_acquire(device
, NULL
);
871 gl_info
= context
->gl_info
;
874 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
875 checkGLcall("glBindBufferARB");
877 /* This shouldn't happen but could occur if some other function
878 * didn't handle the PBO properly. */
879 if (surface
->resource
.allocatedMemory
)
880 ERR("The surface already has PBO memory allocated.\n");
882 surface
->resource
.allocatedMemory
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
883 checkGLcall("glMapBufferARB");
885 /* Make sure the PBO isn't set anymore in order not to break non-PBO
887 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
888 checkGLcall("glBindBufferARB");
891 context_release(context
);
894 if (!(flags
& (WINED3DLOCK_NO_DIRTY_UPDATE
| WINED3DLOCK_READONLY
)))
897 surface_add_dirty_rect(surface
, NULL
);
904 b
.Right
= rect
->right
;
905 b
.Bottom
= rect
->bottom
;
908 surface_add_dirty_rect(surface
, &b
);
913 static void surface_unmap(struct wined3d_surface
*surface
)
915 struct wined3d_device
*device
= surface
->resource
.device
;
918 TRACE("surface %p.\n", surface
);
920 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
922 if (surface
->flags
& SFLAG_PBO
)
924 const struct wined3d_gl_info
*gl_info
;
925 struct wined3d_context
*context
;
927 TRACE("Freeing PBO memory.\n");
929 context
= context_acquire(device
, NULL
);
930 gl_info
= context
->gl_info
;
933 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
934 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
935 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
936 checkGLcall("glUnmapBufferARB");
938 context_release(context
);
940 surface
->resource
.allocatedMemory
= NULL
;
943 TRACE("dirtyfied %u.\n", surface
->flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
) ? 0 : 1);
945 if (surface
->flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
))
947 TRACE("Not dirtified, nothing to do.\n");
951 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
952 || (device
->fb
.render_targets
&& surface
== device
->fb
.render_targets
[0]))
954 if (wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
)
956 static BOOL warned
= FALSE
;
959 ERR("The application tries to write to the render target, but render target locking is disabled.\n");
965 if (!surface
->dirtyRect
.left
&& !surface
->dirtyRect
.top
966 && surface
->dirtyRect
.right
== surface
->resource
.width
967 && surface
->dirtyRect
.bottom
== surface
->resource
.height
)
973 /* TODO: Proper partial rectangle tracking. */
975 surface
->flags
|= SFLAG_INSYSMEM
;
978 surface_load_location(surface
, SFLAG_INDRAWABLE
, fullsurface
? NULL
: &surface
->dirtyRect
);
980 /* Partial rectangle tracking is not commonly implemented, it is only
981 * done for render targets. INSYSMEM was set before to tell
982 * surface_load_location() where to read the rectangle from.
983 * Indrawable is set because all modifications from the partial
984 * sysmem copy are written back to the drawable, thus the surface is
985 * merged again in the drawable. The sysmem copy is not fully up to
986 * date because only a subrectangle was read in Map(). */
989 surface_modify_location(surface
, SFLAG_INDRAWABLE
, TRUE
);
990 surface_evict_sysmem(surface
);
993 surface
->dirtyRect
.left
= surface
->resource
.width
;
994 surface
->dirtyRect
.top
= surface
->resource
.height
;
995 surface
->dirtyRect
.right
= 0;
996 surface
->dirtyRect
.bottom
= 0;
998 else if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
1000 FIXME("Depth / stencil buffer locking is not implemented.\n");
1004 /* Overlays have to be redrawn manually after changes with the GL implementation */
1005 if (surface
->overlay_dest
)
1006 surface
->surface_ops
->surface_draw_overlay(surface
);
1009 static HRESULT
surface_getdc(struct wined3d_surface
*surface
)
1011 WINED3DLOCKED_RECT lock
;
1014 TRACE("surface %p.\n", surface
);
1016 /* Create a DIB section if there isn't a dc yet. */
1019 if (surface
->flags
& SFLAG_CLIENT
)
1021 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
1022 surface_release_client_storage(surface
);
1024 hr
= surface_create_dib_section(surface
);
1026 return WINED3DERR_INVALIDCALL
;
1028 /* Use the DIB section from now on if we are not using a PBO. */
1029 if (!(surface
->flags
& SFLAG_PBO
))
1030 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1033 /* Map the surface. */
1034 hr
= wined3d_surface_map(surface
, &lock
, NULL
, 0);
1036 ERR("Map failed, hr %#x.\n", hr
);
1038 /* Sync the DIB with the PBO. This can't be done earlier because Map()
1039 * activates the allocatedMemory. */
1040 if (surface
->flags
& SFLAG_PBO
)
1041 memcpy(surface
->dib
.bitmap_data
, surface
->resource
.allocatedMemory
, surface
->dib
.bitmap_size
);
1046 static HRESULT
surface_flip(struct wined3d_surface
*surface
, struct wined3d_surface
*override
)
1048 TRACE("surface %p, override %p.\n", surface
, override
);
1050 /* Flipping is only supported on render targets and overlays. */
1051 if (!(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_OVERLAY
)))
1053 WARN("Tried to flip a non-render target, non-overlay surface.\n");
1054 return WINEDDERR_NOTFLIPPABLE
;
1057 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1059 flip_surface(surface
, override
);
1061 /* Update the overlay if it is visible */
1062 if (surface
->overlay_dest
)
1063 return surface
->surface_ops
->surface_draw_overlay(surface
);
1071 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
1073 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
1075 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
1080 static void wined3d_surface_depth_blt_fbo(struct wined3d_device
*device
, struct wined3d_surface
*src_surface
,
1081 const RECT
*src_rect
, struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
)
1083 const struct wined3d_gl_info
*gl_info
;
1084 struct wined3d_context
*context
;
1085 DWORD src_mask
, dst_mask
;
1088 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n",
1089 device
, src_surface
, wine_dbgstr_rect(src_rect
),
1090 dst_surface
, wine_dbgstr_rect(dst_rect
));
1092 src_mask
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1093 dst_mask
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1095 if (src_mask
!= dst_mask
)
1097 ERR("Incompatible formats %s and %s.\n",
1098 debug_d3dformat(src_surface
->resource
.format
->id
),
1099 debug_d3dformat(dst_surface
->resource
.format
->id
));
1105 ERR("Not a depth / stencil format: %s.\n",
1106 debug_d3dformat(src_surface
->resource
.format
->id
));
1111 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
1112 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
1113 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
1114 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
1116 /* Make sure the locations are up-to-date. Loading the destination
1117 * surface isn't required if the entire surface is overwritten. */
1118 surface_load_location(src_surface
, SFLAG_INTEXTURE
, NULL
);
1119 if (!surface_is_full_rect(dst_surface
, dst_rect
))
1120 surface_load_location(dst_surface
, SFLAG_INTEXTURE
, NULL
);
1122 context
= context_acquire(device
, NULL
);
1123 if (!context
->valid
)
1125 context_release(context
);
1126 WARN("Invalid context, skipping blit.\n");
1130 gl_info
= context
->gl_info
;
1134 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, SFLAG_INTEXTURE
);
1135 glReadBuffer(GL_NONE
);
1136 checkGLcall("glReadBuffer()");
1137 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1139 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, SFLAG_INTEXTURE
);
1140 context_set_draw_buffer(context
, GL_NONE
);
1141 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1143 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
1145 glDepthMask(GL_TRUE
);
1146 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
1148 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
1150 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
1152 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
1153 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE
));
1156 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
1159 glDisable(GL_SCISSOR_TEST
);
1160 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
1162 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
1163 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
1164 checkGLcall("glBlitFramebuffer()");
1168 if (wined3d_settings
.strict_draw_ordering
)
1169 wglFlush(); /* Flush to ensure ordering across contexts. */
1171 context_release(context
);
1174 /* Blit between surface locations. Onscreen on different swapchains is not supported.
1175 * Depth / stencil is not supported. */
1176 static void surface_blt_fbo(struct wined3d_device
*device
, const WINED3DTEXTUREFILTERTYPE filter
,
1177 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
1178 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
1180 const struct wined3d_gl_info
*gl_info
;
1181 struct wined3d_context
*context
;
1182 RECT src_rect
, dst_rect
;
1186 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
1187 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1188 src_surface
, debug_surflocation(src_location
), wine_dbgstr_rect(src_rect_in
));
1189 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1190 dst_surface
, debug_surflocation(dst_location
), wine_dbgstr_rect(dst_rect_in
));
1192 src_rect
= *src_rect_in
;
1193 dst_rect
= *dst_rect_in
;
1197 case WINED3DTEXF_LINEAR
:
1198 gl_filter
= GL_LINEAR
;
1202 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
1203 case WINED3DTEXF_NONE
:
1204 case WINED3DTEXF_POINT
:
1205 gl_filter
= GL_NEAREST
;
1209 if (src_location
== SFLAG_INDRAWABLE
&& surface_is_offscreen(src_surface
))
1210 src_location
= SFLAG_INTEXTURE
;
1211 if (dst_location
== SFLAG_INDRAWABLE
&& surface_is_offscreen(dst_surface
))
1212 dst_location
= SFLAG_INTEXTURE
;
1214 /* Make sure the locations are up-to-date. Loading the destination
1215 * surface isn't required if the entire surface is overwritten. (And is
1216 * in fact harmful if we're being called by surface_load_location() with
1217 * the purpose of loading the destination surface.) */
1218 surface_load_location(src_surface
, src_location
, NULL
);
1219 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
1220 surface_load_location(dst_surface
, dst_location
, NULL
);
1222 if (src_location
== SFLAG_INDRAWABLE
) context
= context_acquire(device
, src_surface
);
1223 else if (dst_location
== SFLAG_INDRAWABLE
) context
= context_acquire(device
, dst_surface
);
1224 else context
= context_acquire(device
, NULL
);
1226 if (!context
->valid
)
1228 context_release(context
);
1229 WARN("Invalid context, skipping blit.\n");
1233 gl_info
= context
->gl_info
;
1235 if (src_location
== SFLAG_INDRAWABLE
)
1237 TRACE("Source surface %p is onscreen.\n", src_surface
);
1238 buffer
= surface_get_gl_buffer(src_surface
);
1239 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
1243 TRACE("Source surface %p is offscreen.\n", src_surface
);
1244 buffer
= GL_COLOR_ATTACHMENT0
;
1248 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
1249 glReadBuffer(buffer
);
1250 checkGLcall("glReadBuffer()");
1251 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1254 if (dst_location
== SFLAG_INDRAWABLE
)
1256 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
1257 buffer
= surface_get_gl_buffer(dst_surface
);
1258 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
1262 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
1263 buffer
= GL_COLOR_ATTACHMENT0
;
1267 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
1268 context_set_draw_buffer(context
, buffer
);
1269 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1270 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
1272 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
1273 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
1274 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1
));
1275 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2
));
1276 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3
));
1278 glDisable(GL_SCISSOR_TEST
);
1279 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
1281 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
1282 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
1283 checkGLcall("glBlitFramebuffer()");
1287 if (wined3d_settings
.strict_draw_ordering
1288 || (dst_location
== SFLAG_INDRAWABLE
1289 && dst_surface
->container
.u
.swapchain
->front_buffer
== dst_surface
))
1292 context_release(context
);
1295 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
1296 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
1297 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
1299 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
1302 /* Source and/or destination need to be on the GL side */
1303 if (src_pool
== WINED3DPOOL_SYSTEMMEM
|| dst_pool
== WINED3DPOOL_SYSTEMMEM
)
1308 case WINED3D_BLIT_OP_COLOR_BLIT
:
1309 if (!((src_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
1311 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
1315 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1316 if (!(src_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1318 if (!(dst_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1326 if (!(src_format
->id
== dst_format
->id
1327 || (is_identity_fixup(src_format
->color_fixup
)
1328 && is_identity_fixup(dst_format
->color_fixup
))))
1334 /* This function checks if the primary render target uses the 8bit paletted format. */
1335 static BOOL
primary_render_target_is_p8(const struct wined3d_device
*device
)
1337 if (device
->fb
.render_targets
&& device
->fb
.render_targets
[0])
1339 const struct wined3d_surface
*render_target
= device
->fb
.render_targets
[0];
1340 if ((render_target
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
1341 && (render_target
->resource
.format
->id
== WINED3DFMT_P8_UINT
))
1347 static BOOL
surface_convert_color_to_float(const struct wined3d_surface
*surface
,
1348 DWORD color
, WINED3DCOLORVALUE
*float_color
)
1350 const struct wined3d_format
*format
= surface
->resource
.format
;
1351 const struct wined3d_device
*device
= surface
->resource
.device
;
1355 case WINED3DFMT_P8_UINT
:
1356 if (surface
->palette
)
1358 float_color
->r
= surface
->palette
->palents
[color
].peRed
/ 255.0f
;
1359 float_color
->g
= surface
->palette
->palents
[color
].peGreen
/ 255.0f
;
1360 float_color
->b
= surface
->palette
->palents
[color
].peBlue
/ 255.0f
;
1364 float_color
->r
= 0.0f
;
1365 float_color
->g
= 0.0f
;
1366 float_color
->b
= 0.0f
;
1368 float_color
->a
= primary_render_target_is_p8(device
) ? color
/ 255.0f
: 1.0f
;
1371 case WINED3DFMT_B5G6R5_UNORM
:
1372 float_color
->r
= ((color
>> 11) & 0x1f) / 31.0f
;
1373 float_color
->g
= ((color
>> 5) & 0x3f) / 63.0f
;
1374 float_color
->b
= (color
& 0x1f) / 31.0f
;
1375 float_color
->a
= 1.0f
;
1378 case WINED3DFMT_B8G8R8_UNORM
:
1379 case WINED3DFMT_B8G8R8X8_UNORM
:
1380 float_color
->r
= D3DCOLOR_R(color
);
1381 float_color
->g
= D3DCOLOR_G(color
);
1382 float_color
->b
= D3DCOLOR_B(color
);
1383 float_color
->a
= 1.0f
;
1386 case WINED3DFMT_B8G8R8A8_UNORM
:
1387 float_color
->r
= D3DCOLOR_R(color
);
1388 float_color
->g
= D3DCOLOR_G(color
);
1389 float_color
->b
= D3DCOLOR_B(color
);
1390 float_color
->a
= D3DCOLOR_A(color
);
1394 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1401 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1403 const struct wined3d_format
*format
= surface
->resource
.format
;
1407 case WINED3DFMT_S1_UINT_D15_UNORM
:
1408 *float_depth
= depth
/ (float)0x00007fff;
1411 case WINED3DFMT_D16_UNORM
:
1412 *float_depth
= depth
/ (float)0x0000ffff;
1415 case WINED3DFMT_D24_UNORM_S8_UINT
:
1416 case WINED3DFMT_X8D24_UNORM
:
1417 *float_depth
= depth
/ (float)0x00ffffff;
1420 case WINED3DFMT_D32_UNORM
:
1421 *float_depth
= depth
/ (float)0xffffffff;
1425 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1432 /* Do not call while under the GL lock. */
1433 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1435 const struct wined3d_resource
*resource
= &surface
->resource
;
1436 struct wined3d_device
*device
= resource
->device
;
1437 const struct blit_shader
*blitter
;
1439 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_FILL
,
1440 NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
);
1443 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1444 return WINED3DERR_INVALIDCALL
;
1447 return blitter
->depth_fill(device
, surface
, rect
, depth
);
1450 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
1451 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
)
1453 struct wined3d_device
*device
= src_surface
->resource
.device
;
1455 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1456 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1457 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1458 return WINED3DERR_INVALIDCALL
;
1460 wined3d_surface_depth_blt_fbo(device
, src_surface
, src_rect
, dst_surface
, dst_rect
);
1462 surface_modify_ds_location(dst_surface
, SFLAG_DS_OFFSCREEN
,
1463 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1464 surface_modify_location(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
1469 /* Do not call while under the GL lock. */
1470 HRESULT CDECL
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
,
1471 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD flags
,
1472 const WINEDDBLTFX
*fx
, WINED3DTEXTUREFILTERTYPE filter
)
1474 const struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
1475 struct wined3d_device
*device
= dst_surface
->resource
.device
;
1476 DWORD src_ds_flags
, dst_ds_flags
;
1477 RECT src_rect
, dst_rect
;
1479 static const DWORD simple_blit
= WINEDDBLT_ASYNC
1480 | WINEDDBLT_COLORFILL
1482 | WINEDDBLT_DEPTHFILL
1483 | WINEDDBLT_DONOTWAIT
;
1485 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1486 dst_surface
, wine_dbgstr_rect(dst_rect_in
), src_surface
, wine_dbgstr_rect(src_rect_in
),
1487 flags
, fx
, debug_d3dtexturefiltertype(filter
));
1488 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
1490 if ((dst_surface
->flags
& SFLAG_LOCKED
) || (src_surface
&& (src_surface
->flags
& SFLAG_LOCKED
)))
1492 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
1493 return WINEDDERR_SURFACEBUSY
;
1496 surface_get_rect(dst_surface
, dst_rect_in
, &dst_rect
);
1498 if (dst_rect
.left
>= dst_rect
.right
|| dst_rect
.top
>= dst_rect
.bottom
1499 || dst_rect
.left
> dst_surface
->resource
.width
|| dst_rect
.left
< 0
1500 || dst_rect
.top
> dst_surface
->resource
.height
|| dst_rect
.top
< 0
1501 || dst_rect
.right
> dst_surface
->resource
.width
|| dst_rect
.right
< 0
1502 || dst_rect
.bottom
> dst_surface
->resource
.height
|| dst_rect
.bottom
< 0)
1504 /* The destination rect can be out of bounds on the condition
1505 * that a clipper is set for the surface. */
1506 if (dst_surface
->clipper
)
1507 FIXME("Blit clipping not implemented.\n");
1509 WARN("The application gave us a bad destination rectangle without a clipper set.\n");
1510 return WINEDDERR_INVALIDRECT
;
1515 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
1517 if (src_rect
.left
>= src_rect
.right
|| src_rect
.top
>= src_rect
.bottom
1518 || src_rect
.left
> src_surface
->resource
.width
|| src_rect
.left
< 0
1519 || src_rect
.top
> src_surface
->resource
.height
|| src_rect
.top
< 0
1520 || src_rect
.right
> src_surface
->resource
.width
|| src_rect
.right
< 0
1521 || src_rect
.bottom
> src_surface
->resource
.height
|| src_rect
.bottom
< 0)
1523 WARN("Application gave us bad source rectangle for Blt.\n");
1524 return WINEDDERR_INVALIDRECT
;
1529 memset(&src_rect
, 0, sizeof(src_rect
));
1532 if (!fx
|| !(fx
->dwDDFX
))
1533 flags
&= ~WINEDDBLT_DDFX
;
1535 if (flags
& WINEDDBLT_WAIT
)
1536 flags
&= ~WINEDDBLT_WAIT
;
1538 if (flags
& WINEDDBLT_ASYNC
)
1540 static unsigned int once
;
1543 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
1544 flags
&= ~WINEDDBLT_ASYNC
;
1547 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
1548 if (flags
& WINEDDBLT_DONOTWAIT
)
1550 static unsigned int once
;
1553 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
1554 flags
&= ~WINEDDBLT_DONOTWAIT
;
1557 if (!device
->d3d_initialized
)
1559 WARN("D3D not initialized, using fallback.\n");
1563 if (flags
& ~simple_blit
)
1565 WARN("Using fallback for complex blit (%#x).\n", flags
);
1569 if (src_surface
&& src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
1570 src_swapchain
= src_surface
->container
.u
.swapchain
;
1572 src_swapchain
= NULL
;
1574 if (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
1575 dst_swapchain
= dst_surface
->container
.u
.swapchain
;
1577 dst_swapchain
= NULL
;
1579 /* This isn't strictly needed. FBO blits for example could deal with
1580 * cross-swapchain blits by first downloading the source to a texture
1581 * before switching to the destination context. We just have this here to
1582 * not have to deal with the issue, since cross-swapchain blits should be
1584 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
1586 FIXME("Using fallback for cross-swapchain blit.\n");
1590 dst_ds_flags
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1592 src_ds_flags
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1596 if (src_ds_flags
|| dst_ds_flags
)
1598 if (flags
& WINEDDBLT_DEPTHFILL
)
1602 TRACE("Depth fill.\n");
1604 if (!surface_convert_depth_to_float(dst_surface
, fx
->u5
.dwFillDepth
, &depth
))
1605 return WINED3DERR_INVALIDCALL
;
1607 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, &dst_rect
, depth
)))
1612 /* Accessing depth / stencil surfaces is supposed to fail while in
1613 * a scene, except for fills, which seem to work. */
1614 if (device
->inScene
)
1616 WARN("Rejecting depth / stencil access while in scene.\n");
1617 return WINED3DERR_INVALIDCALL
;
1620 if (src_ds_flags
!= dst_ds_flags
)
1622 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
1623 return WINED3DERR_INVALIDCALL
;
1626 if (src_rect
.top
|| src_rect
.left
1627 || src_rect
.bottom
!= src_surface
->resource
.height
1628 || src_rect
.right
!= src_surface
->resource
.width
)
1630 WARN("Rejecting depth / stencil blit with invalid source rect %s.\n",
1631 wine_dbgstr_rect(&src_rect
));
1632 return WINED3DERR_INVALIDCALL
;
1635 if (dst_rect
.top
|| dst_rect
.left
1636 || dst_rect
.bottom
!= dst_surface
->resource
.height
1637 || dst_rect
.right
!= dst_surface
->resource
.width
)
1639 WARN("Rejecting depth / stencil blit with invalid destination rect %s.\n",
1640 wine_dbgstr_rect(&src_rect
));
1641 return WINED3DERR_INVALIDCALL
;
1644 if (src_surface
->resource
.height
!= dst_surface
->resource
.height
1645 || src_surface
->resource
.width
!= dst_surface
->resource
.width
)
1647 WARN("Rejecting depth / stencil blit with mismatched surface sizes.\n");
1648 return WINED3DERR_INVALIDCALL
;
1651 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
1657 if (flags
& WINEDDBLT_COLORFILL
)
1659 WINED3DCOLORVALUE color
;
1661 TRACE("Color fill.\n");
1663 if (!surface_convert_color_to_float(dst_surface
, fx
->u5
.dwFillColor
, &color
))
1666 if (SUCCEEDED(surface_color_fill(dst_surface
, &dst_rect
, &color
)))
1671 TRACE("Color blit.\n");
1673 if (fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
1674 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1675 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1677 TRACE("Using FBO blit.\n");
1679 surface_blt_fbo(device
, filter
,
1680 src_surface
, SFLAG_INDRAWABLE
, &src_rect
,
1681 dst_surface
, SFLAG_INDRAWABLE
, &dst_rect
);
1682 surface_modify_location(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
1690 /* Special cases for render targets. */
1691 if ((dst_surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
1692 || (src_surface
&& (src_surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)))
1694 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface
, &dst_rect
,
1695 src_surface
, &src_rect
, flags
, fx
, filter
)))
1701 /* For the rest call the X11 surface implementation. For render targets
1702 * this should be implemented OpenGL accelerated in BltOverride, other
1703 * blits are rather rare. */
1704 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
1707 /* Do not call while under the GL lock. */
1708 HRESULT CDECL
wined3d_surface_bltfast(struct wined3d_surface
*dst_surface
, DWORD dst_x
, DWORD dst_y
,
1709 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD trans
)
1711 RECT src_rect
, dst_rect
;
1714 TRACE("dst_surface %p, dst_x %u, dst_y %u, src_surface %p, src_rect_in %s, trans %#x.\n",
1715 dst_surface
, dst_x
, dst_y
, src_surface
, wine_dbgstr_rect(src_rect_in
), trans
);
1717 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
1719 dst_rect
.left
= dst_x
;
1720 dst_rect
.top
= dst_y
;
1721 dst_rect
.right
= dst_x
+ src_rect
.right
- src_rect
.left
;
1722 dst_rect
.bottom
= dst_y
+ src_rect
.bottom
- src_rect
.top
;
1724 if (trans
& WINEDDBLTFAST_SRCCOLORKEY
)
1725 flags
|= WINEDDBLT_KEYSRC
;
1726 if (trans
& WINEDDBLTFAST_DESTCOLORKEY
)
1727 flags
|= WINEDDBLT_KEYDEST
;
1728 if (trans
& WINEDDBLTFAST_WAIT
)
1729 flags
|= WINEDDBLT_WAIT
;
1730 if (trans
& WINEDDBLTFAST_DONOTWAIT
)
1731 flags
|= WINEDDBLT_DONOTWAIT
;
1733 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, NULL
, WINED3DTEXF_POINT
);
1736 static HRESULT
surface_set_mem(struct wined3d_surface
*surface
, void *mem
)
1738 TRACE("surface %p, mem %p.\n", surface
, mem
);
1740 if (mem
&& mem
!= surface
->resource
.allocatedMemory
)
1742 void *release
= NULL
;
1744 /* Do I have to copy the old surface content? */
1745 if (surface
->flags
& SFLAG_DIBSECTION
)
1747 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
1748 DeleteDC(surface
->hDC
);
1749 /* Release the DIB section. */
1750 DeleteObject(surface
->dib
.DIBsection
);
1751 surface
->dib
.bitmap_data
= NULL
;
1752 surface
->resource
.allocatedMemory
= NULL
;
1753 surface
->hDC
= NULL
;
1754 surface
->flags
&= ~SFLAG_DIBSECTION
;
1756 else if (!(surface
->flags
& SFLAG_USERPTR
))
1758 release
= surface
->resource
.heapMemory
;
1759 surface
->resource
.heapMemory
= NULL
;
1761 surface
->resource
.allocatedMemory
= mem
;
1762 surface
->flags
|= SFLAG_USERPTR
;
1764 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
1765 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
1767 /* For client textures OpenGL has to be notified. */
1768 if (surface
->flags
& SFLAG_CLIENT
)
1769 surface_release_client_storage(surface
);
1771 /* Now free the old memory if any. */
1772 HeapFree(GetProcessHeap(), 0, release
);
1774 else if (surface
->flags
& SFLAG_USERPTR
)
1776 /* Map and GetDC will re-create the dib section and allocated memory. */
1777 surface
->resource
.allocatedMemory
= NULL
;
1778 /* HeapMemory should be NULL already. */
1779 if (surface
->resource
.heapMemory
)
1780 ERR("User pointer surface has heap memory allocated.\n");
1781 surface
->flags
&= ~(SFLAG_USERPTR
| SFLAG_INSYSMEM
);
1783 if (surface
->flags
& SFLAG_CLIENT
)
1784 surface_release_client_storage(surface
);
1786 surface_prepare_system_memory(surface
);
1787 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
1793 /* Context activation is done by the caller. */
1794 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1796 if (!surface
->resource
.heapMemory
)
1798 surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
+ RESOURCE_ALIGNMENT
);
1799 surface
->resource
.allocatedMemory
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
1800 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
1804 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
1805 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
1806 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0,
1807 surface
->resource
.size
, surface
->resource
.allocatedMemory
));
1808 checkGLcall("glGetBufferSubDataARB");
1809 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
1810 checkGLcall("glDeleteBuffersARB");
1814 surface
->flags
&= ~SFLAG_PBO
;
1817 /* Do not call while under the GL lock. */
1818 static void surface_unload(struct wined3d_resource
*resource
)
1820 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1821 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1822 struct wined3d_device
*device
= resource
->device
;
1823 const struct wined3d_gl_info
*gl_info
;
1824 struct wined3d_context
*context
;
1826 TRACE("surface %p.\n", surface
);
1828 if (resource
->pool
== WINED3DPOOL_DEFAULT
)
1830 /* Default pool resources are supposed to be destroyed before Reset is called.
1831 * Implicit resources stay however. So this means we have an implicit render target
1832 * or depth stencil. The content may be destroyed, but we still have to tear down
1833 * opengl resources, so we cannot leave early.
1835 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1836 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1837 * or the depth stencil into an FBO the texture or render buffer will be removed
1838 * and all flags get lost
1840 surface_init_sysmem(surface
);
1844 /* Load the surface into system memory */
1845 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
1846 surface_modify_location(surface
, SFLAG_INDRAWABLE
, FALSE
);
1848 surface_modify_location(surface
, SFLAG_INTEXTURE
, FALSE
);
1849 surface_modify_location(surface
, SFLAG_INSRGBTEX
, FALSE
);
1850 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
1852 context
= context_acquire(device
, NULL
);
1853 gl_info
= context
->gl_info
;
1855 /* Destroy PBOs, but load them into real sysmem before */
1856 if (surface
->flags
& SFLAG_PBO
)
1857 surface_remove_pbo(surface
, gl_info
);
1859 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1860 * all application-created targets the application has to release the surface
1861 * before calling _Reset
1863 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1866 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1868 list_remove(&entry
->entry
);
1869 HeapFree(GetProcessHeap(), 0, entry
);
1871 list_init(&surface
->renderbuffers
);
1872 surface
->current_renderbuffer
= NULL
;
1874 /* If we're in a texture, the texture name belongs to the texture.
1875 * Otherwise, destroy it. */
1876 if (surface
->container
.type
!= WINED3D_CONTAINER_TEXTURE
)
1879 glDeleteTextures(1, &surface
->texture_name
);
1880 surface
->texture_name
= 0;
1881 glDeleteTextures(1, &surface
->texture_name_srgb
);
1882 surface
->texture_name_srgb
= 0;
1886 context_release(context
);
1888 resource_unload(resource
);
1891 static const struct wined3d_resource_ops surface_resource_ops
=
1896 static const struct wined3d_surface_ops surface_ops
=
1898 surface_private_setup
,
1900 surface_realize_palette
,
1901 surface_draw_overlay
,
1910 /*****************************************************************************
1911 * Initializes the GDI surface, aka creates the DIB section we render to
1912 * The DIB section creation is done by calling GetDC, which will create the
1913 * section and releasing the dc to allow the app to use it. The dib section
1914 * will stay until the surface is released
1916 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1917 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1918 * avoid confusion in the shared surface code.
1921 * WINED3D_OK on success
1922 * The return values of called methods on failure
1924 *****************************************************************************/
1925 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1929 TRACE("surface %p.\n", surface
);
1931 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1933 ERR("Overlays not yet supported by GDI surfaces.\n");
1934 return WINED3DERR_INVALIDCALL
;
1937 /* Sysmem textures have memory already allocated - release it,
1938 * this avoids an unnecessary memcpy. */
1939 hr
= surface_create_dib_section(surface
);
1942 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
1943 surface
->resource
.heapMemory
= NULL
;
1944 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1947 /* We don't mind the nonpow2 stuff in GDI. */
1948 surface
->pow2Width
= surface
->resource
.width
;
1949 surface
->pow2Height
= surface
->resource
.height
;
1954 static void surface_gdi_cleanup(struct wined3d_surface
*surface
)
1956 TRACE("surface %p.\n", surface
);
1958 if (surface
->flags
& SFLAG_DIBSECTION
)
1960 /* Release the DC. */
1961 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
1962 DeleteDC(surface
->hDC
);
1963 /* Release the DIB section. */
1964 DeleteObject(surface
->dib
.DIBsection
);
1965 surface
->dib
.bitmap_data
= NULL
;
1966 surface
->resource
.allocatedMemory
= NULL
;
1969 if (surface
->flags
& SFLAG_USERPTR
)
1970 wined3d_surface_set_mem(surface
, NULL
);
1971 if (surface
->overlay_dest
)
1972 list_remove(&surface
->overlay_entry
);
1974 HeapFree(GetProcessHeap(), 0, surface
->palette9
);
1976 resource_cleanup(&surface
->resource
);
1979 static void gdi_surface_realize_palette(struct wined3d_surface
*surface
)
1981 struct wined3d_palette
*palette
= surface
->palette
;
1983 TRACE("surface %p.\n", surface
);
1985 if (!palette
) return;
1987 if (surface
->flags
& SFLAG_DIBSECTION
)
1992 TRACE("Updating the DC's palette.\n");
1994 for (i
= 0; i
< 256; ++i
)
1996 col
[i
].rgbRed
= palette
->palents
[i
].peRed
;
1997 col
[i
].rgbGreen
= palette
->palents
[i
].peGreen
;
1998 col
[i
].rgbBlue
= palette
->palents
[i
].peBlue
;
1999 col
[i
].rgbReserved
= 0;
2001 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
2004 /* Update the image because of the palette change. Some games like e.g.
2005 * Red Alert call SetEntries a lot to implement fading. */
2006 /* Tell the swapchain to update the screen. */
2007 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
2009 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
2010 if (surface
== swapchain
->front_buffer
)
2012 x11_copy_to_screen(swapchain
, NULL
);
2017 static HRESULT
gdi_surface_draw_overlay(struct wined3d_surface
*surface
)
2019 FIXME("GDI surfaces can't draw overlays yet.\n");
2023 static void gdi_surface_preload(struct wined3d_surface
*surface
)
2025 TRACE("surface %p.\n", surface
);
2027 ERR("Preloading GDI surfaces is not supported.\n");
2030 static void gdi_surface_map(struct wined3d_surface
*surface
, const RECT
*rect
, DWORD flags
)
2032 TRACE("surface %p, rect %s, flags %#x.\n",
2033 surface
, wine_dbgstr_rect(rect
), flags
);
2035 if (!surface
->resource
.allocatedMemory
)
2037 /* This happens on gdi surfaces if the application set a user pointer
2038 * and resets it. Recreate the DIB section. */
2039 surface_create_dib_section(surface
);
2040 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
2044 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
2046 TRACE("surface %p.\n", surface
);
2048 /* Tell the swapchain to update the screen. */
2049 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
2051 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
2052 if (surface
== swapchain
->front_buffer
)
2054 x11_copy_to_screen(swapchain
, &surface
->lockedRect
);
2058 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
2061 static HRESULT
gdi_surface_getdc(struct wined3d_surface
*surface
)
2063 WINED3DLOCKED_RECT lock
;
2066 TRACE("surface %p.\n", surface
);
2068 /* Should have a DIB section already. */
2069 if (!(surface
->flags
& SFLAG_DIBSECTION
))
2071 WARN("DC not supported on this surface\n");
2072 return WINED3DERR_INVALIDCALL
;
2075 /* Map the surface. */
2076 hr
= wined3d_surface_map(surface
, &lock
, NULL
, 0);
2078 ERR("Map failed, hr %#x.\n", hr
);
2083 static HRESULT
gdi_surface_flip(struct wined3d_surface
*surface
, struct wined3d_surface
*override
)
2085 TRACE("surface %p, override %p.\n", surface
, override
);
2090 static HRESULT
gdi_surface_set_mem(struct wined3d_surface
*surface
, void *mem
)
2092 TRACE("surface %p, mem %p.\n", surface
, mem
);
2094 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
2095 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
2097 ERR("Not supported on render targets.\n");
2098 return WINED3DERR_INVALIDCALL
;
2101 if (mem
&& mem
!= surface
->resource
.allocatedMemory
)
2103 void *release
= NULL
;
2105 /* Do I have to copy the old surface content? */
2106 if (surface
->flags
& SFLAG_DIBSECTION
)
2108 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
2109 DeleteDC(surface
->hDC
);
2110 /* Release the DIB section. */
2111 DeleteObject(surface
->dib
.DIBsection
);
2112 surface
->dib
.bitmap_data
= NULL
;
2113 surface
->resource
.allocatedMemory
= NULL
;
2114 surface
->hDC
= NULL
;
2115 surface
->flags
&= ~SFLAG_DIBSECTION
;
2117 else if (!(surface
->flags
& SFLAG_USERPTR
))
2119 release
= surface
->resource
.allocatedMemory
;
2121 surface
->resource
.allocatedMemory
= mem
;
2122 surface
->flags
|= SFLAG_USERPTR
| SFLAG_INSYSMEM
;
2124 /* Now free the old memory, if any. */
2125 HeapFree(GetProcessHeap(), 0, release
);
2127 else if (surface
->flags
& SFLAG_USERPTR
)
2129 /* Map() and GetDC() will re-create the dib section and allocated memory. */
2130 surface
->resource
.allocatedMemory
= NULL
;
2131 surface
->flags
&= ~SFLAG_USERPTR
;
2137 static const struct wined3d_surface_ops gdi_surface_ops
=
2139 gdi_surface_private_setup
,
2140 surface_gdi_cleanup
,
2141 gdi_surface_realize_palette
,
2142 gdi_surface_draw_overlay
,
2143 gdi_surface_preload
,
2148 gdi_surface_set_mem
,
2151 void surface_set_texture_name(struct wined3d_surface
*surface
, GLuint new_name
, BOOL srgb
)
2156 TRACE("surface %p, new_name %u, srgb %#x.\n", surface
, new_name
, srgb
);
2160 name
= &surface
->texture_name_srgb
;
2161 flag
= SFLAG_INSRGBTEX
;
2165 name
= &surface
->texture_name
;
2166 flag
= SFLAG_INTEXTURE
;
2169 if (!*name
&& new_name
)
2171 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
2172 * surface has no texture name yet. See if we can get rid of this. */
2173 if (surface
->flags
& flag
)
2174 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag
));
2175 surface_modify_location(surface
, flag
, FALSE
);
2179 surface_force_reload(surface
);
2182 void surface_set_texture_target(struct wined3d_surface
*surface
, GLenum target
)
2184 TRACE("surface %p, target %#x.\n", surface
, target
);
2186 if (surface
->texture_target
!= target
)
2188 if (target
== GL_TEXTURE_RECTANGLE_ARB
)
2190 surface
->flags
&= ~SFLAG_NORMCOORD
;
2192 else if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
2194 surface
->flags
|= SFLAG_NORMCOORD
;
2197 surface
->texture_target
= target
;
2198 surface_force_reload(surface
);
2201 /* Context activation is done by the caller. */
2202 void surface_bind(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL srgb
)
2204 TRACE("surface %p, gl_info %p, srgb %#x.\n", surface
, gl_info
, srgb
);
2206 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
2208 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
2210 TRACE("Passing to container (%p).\n", texture
);
2211 texture
->texture_ops
->texture_bind(texture
, gl_info
, srgb
);
2215 if (surface
->texture_level
)
2217 ERR("Standalone surface %p is non-zero texture level %u.\n",
2218 surface
, surface
->texture_level
);
2222 ERR("Trying to bind standalone surface %p as sRGB.\n", surface
);
2226 if (!surface
->texture_name
)
2228 glGenTextures(1, &surface
->texture_name
);
2229 checkGLcall("glGenTextures");
2231 TRACE("Surface %p given name %u.\n", surface
, surface
->texture_name
);
2233 glBindTexture(surface
->texture_target
, surface
->texture_name
);
2234 checkGLcall("glBindTexture");
2235 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2236 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2237 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
2238 glTexParameteri(surface
->texture_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2239 glTexParameteri(surface
->texture_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2240 checkGLcall("glTexParameteri");
2244 glBindTexture(surface
->texture_target
, surface
->texture_name
);
2245 checkGLcall("glBindTexture");
2252 /* This call just downloads data, the caller is responsible for binding the
2253 * correct texture. */
2254 /* Context activation is done by the caller. */
2255 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
2257 const struct wined3d_format
*format
= surface
->resource
.format
;
2259 /* Only support read back of converted P8 surfaces. */
2260 if (surface
->flags
& SFLAG_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
2262 FIXME("Readback conversion not supported for format %s.\n", debug_d3dformat(format
->id
));
2268 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
2270 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2271 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
,
2272 surface
->resource
.allocatedMemory
);
2274 if (surface
->flags
& SFLAG_PBO
)
2276 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
2277 checkGLcall("glBindBufferARB");
2278 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
, surface
->texture_level
, NULL
));
2279 checkGLcall("glGetCompressedTexImageARB");
2280 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
2281 checkGLcall("glBindBufferARB");
2285 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
,
2286 surface
->texture_level
, surface
->resource
.allocatedMemory
));
2287 checkGLcall("glGetCompressedTexImageARB");
2295 GLenum gl_format
= format
->glFormat
;
2296 GLenum gl_type
= format
->glType
;
2300 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
2301 if (format
->id
== WINED3DFMT_P8_UINT
&& primary_render_target_is_p8(surface
->resource
.device
))
2303 gl_format
= GL_ALPHA
;
2304 gl_type
= GL_UNSIGNED_BYTE
;
2307 if (surface
->flags
& SFLAG_NONPOW2
)
2309 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
2310 src_pitch
= format
->byte_count
* surface
->pow2Width
;
2311 dst_pitch
= wined3d_surface_get_pitch(surface
);
2312 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
2313 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
2317 mem
= surface
->resource
.allocatedMemory
;
2320 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2321 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
2323 if (surface
->flags
& SFLAG_PBO
)
2325 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
2326 checkGLcall("glBindBufferARB");
2328 glGetTexImage(surface
->texture_target
, surface
->texture_level
, gl_format
, gl_type
, NULL
);
2329 checkGLcall("glGetTexImage");
2331 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
2332 checkGLcall("glBindBufferARB");
2336 glGetTexImage(surface
->texture_target
, surface
->texture_level
, gl_format
, gl_type
, mem
);
2337 checkGLcall("glGetTexImage");
2341 if (surface
->flags
& SFLAG_NONPOW2
)
2343 const BYTE
*src_data
;
2347 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2348 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2349 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2351 * We're doing this...
2353 * instead of boxing the texture :
2354 * |<-texture width ->| -->pow2width| /\
2355 * |111111111111111111| | |
2356 * |222 Texture 222222| boxed empty | texture height
2357 * |3333 Data 33333333| | |
2358 * |444444444444444444| | \/
2359 * ----------------------------------- |
2360 * | boxed empty | boxed empty | pow2height
2362 * -----------------------------------
2365 * we're repacking the data to the expected texture width
2367 * |<-texture width ->| -->pow2width| /\
2368 * |111111111111111111222222222222222| |
2369 * |222333333333333333333444444444444| texture height
2373 * | empty | pow2height
2375 * -----------------------------------
2379 * |<-texture width ->| /\
2380 * |111111111111111111|
2381 * |222222222222222222|texture height
2382 * |333333333333333333|
2383 * |444444444444444444| \/
2384 * --------------------
2386 * this also means that any references to allocatedMemory should work with the data as if were a
2387 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2389 * internally the texture is still stored in a boxed format so any references to textureName will
2390 * get a boxed texture with width pow2width and not a texture of width resource.width.
2392 * Performance should not be an issue, because applications normally do not lock the surfaces when
2393 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2394 * and doesn't have to be re-read. */
2396 dst_data
= surface
->resource
.allocatedMemory
;
2397 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_pitch
);
2398 for (y
= 1; y
< surface
->resource
.height
; ++y
)
2400 /* skip the first row */
2401 src_data
+= src_pitch
;
2402 dst_data
+= dst_pitch
;
2403 memcpy(dst_data
, src_data
, dst_pitch
);
2406 HeapFree(GetProcessHeap(), 0, mem
);
2410 /* Surface has now been downloaded */
2411 surface
->flags
|= SFLAG_INSYSMEM
;
2414 /* This call just uploads data, the caller is responsible for binding the
2415 * correct texture. */
2416 /* Context activation is done by the caller. */
2417 void surface_upload_data(const struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
2418 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_w
, const POINT
*dst_point
,
2419 BOOL srgb
, const struct wined3d_bo_address
*data
)
2421 UINT update_w
= src_rect
->right
- src_rect
->left
;
2422 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
2424 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_w %u, dst_point %p, srgb %#x, data {%#x:%p}.\n",
2425 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_w
,
2426 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
2428 if (format
->heightscale
!= 1.0f
&& format
->heightscale
!= 0.0f
)
2429 update_h
*= format
->heightscale
;
2433 if (data
->buffer_object
)
2435 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, data
->buffer_object
));
2436 checkGLcall("glBindBufferARB");
2439 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
2441 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1);
2442 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
2443 UINT src_pitch
= wined3d_format_calculate_size(format
, 1, src_w
, 1);
2444 const BYTE
*addr
= data
->addr
;
2447 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
2448 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
2451 internal
= format
->glGammaInternal
;
2452 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
2453 internal
= format
->rtInternal
;
2455 internal
= format
->glInternal
;
2457 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
2458 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
2459 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
2461 if (row_length
== src_pitch
)
2463 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
2464 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
2470 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
2471 * can't use the unpack row length like below. */
2472 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
2474 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
2475 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
2476 y
+= format
->block_height
;
2480 checkGLcall("glCompressedTexSubImage2DARB");
2484 const BYTE
*addr
= data
->addr
;
2486 addr
+= src_rect
->top
* src_w
* format
->byte_count
;
2487 addr
+= src_rect
->left
* format
->byte_count
;
2489 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
2490 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
2491 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
2493 glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_w
);
2494 glTexSubImage2D(surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
2495 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
2496 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
2497 checkGLcall("glTexSubImage2D");
2500 if (data
->buffer_object
)
2502 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
2503 checkGLcall("glBindBufferARB");
2508 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
2510 struct wined3d_device
*device
= surface
->resource
.device
;
2513 for (i
= 0; i
< device
->context_count
; ++i
)
2515 context_surface_update(device
->contexts
[i
], surface
);
2520 /* This call just allocates the texture, the caller is responsible for binding
2521 * the correct texture. */
2522 /* Context activation is done by the caller. */
2523 static void surface_allocate_surface(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
2524 const struct wined3d_format
*format
, BOOL srgb
)
2526 BOOL enable_client_storage
= FALSE
;
2527 GLsizei width
= surface
->pow2Width
;
2528 GLsizei height
= surface
->pow2Height
;
2529 const BYTE
*mem
= NULL
;
2534 internal
= format
->glGammaInternal
;
2536 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
2538 internal
= format
->rtInternal
;
2542 internal
= format
->glInternal
;
2545 if (format
->heightscale
!= 1.0f
&& format
->heightscale
!= 0.0f
) height
*= format
->heightscale
;
2547 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",
2548 surface
, surface
->texture_target
, surface
->texture_level
, debug_d3dformat(format
->id
),
2549 internal
, width
, height
, format
->glFormat
, format
->glType
);
2553 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
2555 if (surface
->flags
& (SFLAG_NONPOW2
| SFLAG_DIBSECTION
| SFLAG_CONVERTED
)
2556 || !surface
->resource
.allocatedMemory
)
2558 /* In some cases we want to disable client storage.
2559 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2560 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2561 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2562 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2564 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2565 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2566 surface
->flags
&= ~SFLAG_CLIENT
;
2567 enable_client_storage
= TRUE
;
2571 surface
->flags
|= SFLAG_CLIENT
;
2573 /* Point OpenGL to our allocated texture memory. Do not use
2574 * resource.allocatedMemory here because it might point into a
2575 * PBO. Instead use heapMemory, but get the alignment right. */
2576 mem
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
2577 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
2581 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
&& mem
)
2583 GL_EXTCALL(glCompressedTexImage2DARB(surface
->texture_target
, surface
->texture_level
,
2584 internal
, width
, height
, 0, surface
->resource
.size
, mem
));
2585 checkGLcall("glCompressedTexImage2DARB");
2589 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
2590 internal
, width
, height
, 0, format
->glFormat
, format
->glType
, mem
);
2591 checkGLcall("glTexImage2D");
2594 if(enable_client_storage
) {
2595 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2596 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2601 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2602 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2603 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2604 /* GL locking is done by the caller */
2605 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
2607 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
2608 struct wined3d_renderbuffer_entry
*entry
;
2609 GLuint renderbuffer
= 0;
2610 unsigned int src_width
, src_height
;
2611 unsigned int width
, height
;
2613 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
2615 width
= rt
->pow2Width
;
2616 height
= rt
->pow2Height
;
2620 width
= surface
->pow2Width
;
2621 height
= surface
->pow2Height
;
2624 src_width
= surface
->pow2Width
;
2625 src_height
= surface
->pow2Height
;
2627 /* A depth stencil smaller than the render target is not valid */
2628 if (width
> src_width
|| height
> src_height
) return;
2630 /* Remove any renderbuffer set if the sizes match */
2631 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
2632 || (width
== src_width
&& height
== src_height
))
2634 surface
->current_renderbuffer
= NULL
;
2638 /* Look if we've already got a renderbuffer of the correct dimensions */
2639 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
2641 if (entry
->width
== width
&& entry
->height
== height
)
2643 renderbuffer
= entry
->id
;
2644 surface
->current_renderbuffer
= entry
;
2651 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
2652 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
2653 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
2654 surface
->resource
.format
->glInternal
, width
, height
);
2656 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
2657 entry
->width
= width
;
2658 entry
->height
= height
;
2659 entry
->id
= renderbuffer
;
2660 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
2662 surface
->current_renderbuffer
= entry
;
2665 checkGLcall("set_compatible_renderbuffer");
2668 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
2670 const struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
2672 TRACE("surface %p.\n", surface
);
2674 if (surface
->container
.type
!= WINED3D_CONTAINER_SWAPCHAIN
)
2676 ERR("Surface %p is not on a swapchain.\n", surface
);
2680 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
)
2682 if (swapchain
->render_to_fbo
)
2684 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2685 return GL_COLOR_ATTACHMENT0
;
2687 TRACE("Returning GL_BACK\n");
2690 else if (surface
== swapchain
->front_buffer
)
2692 TRACE("Returning GL_FRONT\n");
2696 FIXME("Higher back buffer, returning GL_BACK\n");
2700 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
2701 void surface_add_dirty_rect(struct wined3d_surface
*surface
, const WINED3DBOX
*dirty_rect
)
2703 TRACE("surface %p, dirty_rect %p.\n", surface
, dirty_rect
);
2705 if (!(surface
->flags
& SFLAG_INSYSMEM
) && (surface
->flags
& SFLAG_INTEXTURE
))
2706 /* No partial locking for textures yet. */
2707 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
2709 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
2712 surface
->dirtyRect
.left
= min(surface
->dirtyRect
.left
, dirty_rect
->Left
);
2713 surface
->dirtyRect
.top
= min(surface
->dirtyRect
.top
, dirty_rect
->Top
);
2714 surface
->dirtyRect
.right
= max(surface
->dirtyRect
.right
, dirty_rect
->Right
);
2715 surface
->dirtyRect
.bottom
= max(surface
->dirtyRect
.bottom
, dirty_rect
->Bottom
);
2719 surface
->dirtyRect
.left
= 0;
2720 surface
->dirtyRect
.top
= 0;
2721 surface
->dirtyRect
.right
= surface
->resource
.width
;
2722 surface
->dirtyRect
.bottom
= surface
->resource
.height
;
2725 /* if the container is a texture then mark it dirty. */
2726 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
2728 TRACE("Passing to container.\n");
2729 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
2733 HRESULT
surface_load(struct wined3d_surface
*surface
, BOOL srgb
)
2735 DWORD flag
= srgb
? SFLAG_INSRGBTEX
: SFLAG_INTEXTURE
;
2738 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
2740 if (surface
->resource
.pool
== WINED3DPOOL_SCRATCH
)
2742 ERR("Not supported on scratch surfaces.\n");
2743 return WINED3DERR_INVALIDCALL
;
2746 ck_changed
= !(surface
->flags
& SFLAG_GLCKEY
) != !(surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
);
2748 /* Reload if either the texture and sysmem have different ideas about the
2749 * color key, or the actual key values changed. */
2750 if (ck_changed
|| ((surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
)
2751 && (surface
->glCKey
.dwColorSpaceLowValue
!= surface
->SrcBltCKey
.dwColorSpaceLowValue
2752 || surface
->glCKey
.dwColorSpaceHighValue
!= surface
->SrcBltCKey
.dwColorSpaceHighValue
)))
2754 TRACE("Reloading because of color keying\n");
2755 /* To perform the color key conversion we need a sysmem copy of
2756 * the surface. Make sure we have it. */
2758 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
2759 /* Make sure the texture is reloaded because of the color key change,
2760 * this kills performance though :( */
2761 /* TODO: This is not necessarily needed with hw palettized texture support. */
2762 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
2763 /* Switching color keying on / off may change the internal format. */
2765 surface_force_reload(surface
);
2767 else if (!(surface
->flags
& flag
))
2769 TRACE("Reloading because surface is dirty.\n");
2773 TRACE("surface is already in texture\n");
2777 /* No partial locking for textures yet. */
2778 surface_load_location(surface
, flag
, NULL
);
2779 surface_evict_sysmem(surface
);
2784 /* See also float_16_to_32() in wined3d_private.h */
2785 static inline unsigned short float_32_to_16(const float *in
)
2788 float tmp
= fabsf(*in
);
2789 unsigned int mantissa
;
2792 /* Deal with special numbers */
2798 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
2800 if (tmp
< powf(2, 10))
2806 } while (tmp
< powf(2, 10));
2808 else if (tmp
>= powf(2, 11))
2814 } while (tmp
>= powf(2, 11));
2817 mantissa
= (unsigned int)tmp
;
2818 if (tmp
- mantissa
>= 0.5f
)
2819 ++mantissa
; /* Round to nearest, away from zero. */
2821 exp
+= 10; /* Normalize the mantissa. */
2822 exp
+= 15; /* Exponent is encoded with excess 15. */
2824 if (exp
> 30) /* too big */
2826 ret
= 0x7c00; /* INF */
2830 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2833 mantissa
= mantissa
>> 1;
2836 ret
= mantissa
& 0x3ff;
2840 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
2843 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
2847 ULONG CDECL
wined3d_surface_incref(struct wined3d_surface
*surface
)
2851 TRACE("Surface %p, container %p of type %#x.\n",
2852 surface
, surface
->container
.u
.base
, surface
->container
.type
);
2854 switch (surface
->container
.type
)
2856 case WINED3D_CONTAINER_TEXTURE
:
2857 return wined3d_texture_incref(surface
->container
.u
.texture
);
2859 case WINED3D_CONTAINER_SWAPCHAIN
:
2860 return wined3d_swapchain_incref(surface
->container
.u
.swapchain
);
2863 ERR("Unhandled container type %#x.\n", surface
->container
.type
);
2864 case WINED3D_CONTAINER_NONE
:
2868 refcount
= InterlockedIncrement(&surface
->resource
.ref
);
2869 TRACE("%p increasing refcount to %u.\n", surface
, refcount
);
2874 /* Do not call while under the GL lock. */
2875 ULONG CDECL
wined3d_surface_decref(struct wined3d_surface
*surface
)
2879 TRACE("Surface %p, container %p of type %#x.\n",
2880 surface
, surface
->container
.u
.base
, surface
->container
.type
);
2882 switch (surface
->container
.type
)
2884 case WINED3D_CONTAINER_TEXTURE
:
2885 return wined3d_texture_decref(surface
->container
.u
.texture
);
2887 case WINED3D_CONTAINER_SWAPCHAIN
:
2888 return wined3d_swapchain_decref(surface
->container
.u
.swapchain
);
2891 ERR("Unhandled container type %#x.\n", surface
->container
.type
);
2892 case WINED3D_CONTAINER_NONE
:
2896 refcount
= InterlockedDecrement(&surface
->resource
.ref
);
2897 TRACE("%p decreasing refcount to %u.\n", surface
, refcount
);
2901 surface
->surface_ops
->surface_cleanup(surface
);
2902 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
2904 TRACE("Destroyed surface %p.\n", surface
);
2905 HeapFree(GetProcessHeap(), 0, surface
);
2911 DWORD CDECL
wined3d_surface_set_priority(struct wined3d_surface
*surface
, DWORD priority
)
2913 return resource_set_priority(&surface
->resource
, priority
);
2916 DWORD CDECL
wined3d_surface_get_priority(const struct wined3d_surface
*surface
)
2918 return resource_get_priority(&surface
->resource
);
2921 void CDECL
wined3d_surface_preload(struct wined3d_surface
*surface
)
2923 TRACE("surface %p.\n", surface
);
2925 surface
->surface_ops
->surface_preload(surface
);
2928 void * CDECL
wined3d_surface_get_parent(const struct wined3d_surface
*surface
)
2930 TRACE("surface %p.\n", surface
);
2932 return surface
->resource
.parent
;
2935 struct wined3d_resource
* CDECL
wined3d_surface_get_resource(struct wined3d_surface
*surface
)
2937 TRACE("surface %p.\n", surface
);
2939 return &surface
->resource
;
2942 HRESULT CDECL
wined3d_surface_get_blt_status(const struct wined3d_surface
*surface
, DWORD flags
)
2944 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2948 case WINEDDGBS_CANBLT
:
2949 case WINEDDGBS_ISBLTDONE
:
2953 return WINED3DERR_INVALIDCALL
;
2957 HRESULT CDECL
wined3d_surface_get_flip_status(const struct wined3d_surface
*surface
, DWORD flags
)
2959 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2961 /* XXX: DDERR_INVALIDSURFACETYPE */
2965 case WINEDDGFS_CANFLIP
:
2966 case WINEDDGFS_ISFLIPDONE
:
2970 return WINED3DERR_INVALIDCALL
;
2974 HRESULT CDECL
wined3d_surface_is_lost(const struct wined3d_surface
*surface
)
2976 TRACE("surface %p.\n", surface
);
2978 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2979 return surface
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
2982 HRESULT CDECL
wined3d_surface_restore(struct wined3d_surface
*surface
)
2984 TRACE("surface %p.\n", surface
);
2986 /* So far we don't lose anything :) */
2987 surface
->flags
&= ~SFLAG_LOST
;
2991 HRESULT CDECL
wined3d_surface_set_palette(struct wined3d_surface
*surface
, struct wined3d_palette
*palette
)
2993 TRACE("surface %p, palette %p.\n", surface
, palette
);
2995 if (surface
->palette
== palette
)
2997 TRACE("Nop palette change.\n");
3001 if (surface
->palette
&& (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
))
3002 surface
->palette
->flags
&= ~WINEDDPCAPS_PRIMARYSURFACE
;
3004 surface
->palette
= palette
;
3008 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
3009 palette
->flags
|= WINEDDPCAPS_PRIMARYSURFACE
;
3011 surface
->surface_ops
->surface_realize_palette(surface
);
3017 HRESULT CDECL
wined3d_surface_set_color_key(struct wined3d_surface
*surface
,
3018 DWORD flags
, const WINEDDCOLORKEY
*color_key
)
3020 TRACE("surface %p, flags %#x, color_key %p.\n", surface
, flags
, color_key
);
3022 if (flags
& WINEDDCKEY_COLORSPACE
)
3024 FIXME(" colorkey value not supported (%08x) !\n", flags
);
3025 return WINED3DERR_INVALIDCALL
;
3028 /* Dirtify the surface, but only if a key was changed. */
3031 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
3033 case WINEDDCKEY_DESTBLT
:
3034 surface
->DestBltCKey
= *color_key
;
3035 surface
->CKeyFlags
|= WINEDDSD_CKDESTBLT
;
3038 case WINEDDCKEY_DESTOVERLAY
:
3039 surface
->DestOverlayCKey
= *color_key
;
3040 surface
->CKeyFlags
|= WINEDDSD_CKDESTOVERLAY
;
3043 case WINEDDCKEY_SRCOVERLAY
:
3044 surface
->SrcOverlayCKey
= *color_key
;
3045 surface
->CKeyFlags
|= WINEDDSD_CKSRCOVERLAY
;
3048 case WINEDDCKEY_SRCBLT
:
3049 surface
->SrcBltCKey
= *color_key
;
3050 surface
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
3056 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
3058 case WINEDDCKEY_DESTBLT
:
3059 surface
->CKeyFlags
&= ~WINEDDSD_CKDESTBLT
;
3062 case WINEDDCKEY_DESTOVERLAY
:
3063 surface
->CKeyFlags
&= ~WINEDDSD_CKDESTOVERLAY
;
3066 case WINEDDCKEY_SRCOVERLAY
:
3067 surface
->CKeyFlags
&= ~WINEDDSD_CKSRCOVERLAY
;
3070 case WINEDDCKEY_SRCBLT
:
3071 surface
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
3079 struct wined3d_palette
* CDECL
wined3d_surface_get_palette(const struct wined3d_surface
*surface
)
3081 TRACE("surface %p.\n", surface
);
3083 return surface
->palette
;
3086 DWORD CDECL
wined3d_surface_get_pitch(const struct wined3d_surface
*surface
)
3088 const struct wined3d_format
*format
= surface
->resource
.format
;
3091 TRACE("surface %p.\n", surface
);
3093 if ((format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_COMPRESSED
)
3095 /* Since compressed formats are block based, pitch means the amount of
3096 * bytes to the next row of block rather than the next row of pixels. */
3097 UINT row_block_count
= (surface
->resource
.width
+ format
->block_width
- 1) / format
->block_width
;
3098 pitch
= row_block_count
* format
->block_byte_count
;
3102 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
3103 pitch
= surface
->resource
.format
->byte_count
* surface
->resource
.width
; /* Bytes / row */
3104 pitch
= (pitch
+ alignment
- 1) & ~(alignment
- 1);
3107 TRACE("Returning %u.\n", pitch
);
3112 HRESULT CDECL
wined3d_surface_set_mem(struct wined3d_surface
*surface
, void *mem
)
3114 TRACE("surface %p, mem %p.\n", surface
, mem
);
3116 if (surface
->flags
& (SFLAG_LOCKED
| SFLAG_DCINUSE
))
3118 WARN("Surface is locked or the DC is in use.\n");
3119 return WINED3DERR_INVALIDCALL
;
3122 return surface
->surface_ops
->surface_set_mem(surface
, mem
);
3125 HRESULT CDECL
wined3d_surface_set_overlay_position(struct wined3d_surface
*surface
, LONG x
, LONG y
)
3129 TRACE("surface %p, x %d, y %d.\n", surface
, x
, y
);
3131 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3133 WARN("Not an overlay surface.\n");
3134 return WINEDDERR_NOTAOVERLAYSURFACE
;
3137 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
3138 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
3139 surface
->overlay_destrect
.left
= x
;
3140 surface
->overlay_destrect
.top
= y
;
3141 surface
->overlay_destrect
.right
= x
+ w
;
3142 surface
->overlay_destrect
.bottom
= y
+ h
;
3144 surface
->surface_ops
->surface_draw_overlay(surface
);
3149 HRESULT CDECL
wined3d_surface_get_overlay_position(const struct wined3d_surface
*surface
, LONG
*x
, LONG
*y
)
3151 TRACE("surface %p, x %p, y %p.\n", surface
, x
, y
);
3153 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3155 TRACE("Not an overlay surface.\n");
3156 return WINEDDERR_NOTAOVERLAYSURFACE
;
3159 if (!surface
->overlay_dest
)
3161 TRACE("Overlay not visible.\n");
3164 return WINEDDERR_OVERLAYNOTVISIBLE
;
3167 *x
= surface
->overlay_destrect
.left
;
3168 *y
= surface
->overlay_destrect
.top
;
3170 TRACE("Returning position %d, %d.\n", *x
, *y
);
3175 HRESULT CDECL
wined3d_surface_update_overlay_z_order(struct wined3d_surface
*surface
,
3176 DWORD flags
, struct wined3d_surface
*ref
)
3178 FIXME("surface %p, flags %#x, ref %p stub!\n", surface
, flags
, ref
);
3180 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3182 TRACE("Not an overlay surface.\n");
3183 return WINEDDERR_NOTAOVERLAYSURFACE
;
3189 HRESULT CDECL
wined3d_surface_update_overlay(struct wined3d_surface
*surface
, const RECT
*src_rect
,
3190 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
, DWORD flags
, const WINEDDOVERLAYFX
*fx
)
3192 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3193 surface
, wine_dbgstr_rect(src_rect
), dst_surface
, wine_dbgstr_rect(dst_rect
), flags
, fx
);
3195 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3197 WARN("Not an overlay surface.\n");
3198 return WINEDDERR_NOTAOVERLAYSURFACE
;
3200 else if (!dst_surface
)
3202 WARN("Dest surface is NULL.\n");
3203 return WINED3DERR_INVALIDCALL
;
3208 surface
->overlay_srcrect
= *src_rect
;
3212 surface
->overlay_srcrect
.left
= 0;
3213 surface
->overlay_srcrect
.top
= 0;
3214 surface
->overlay_srcrect
.right
= surface
->resource
.width
;
3215 surface
->overlay_srcrect
.bottom
= surface
->resource
.height
;
3220 surface
->overlay_destrect
= *dst_rect
;
3224 surface
->overlay_destrect
.left
= 0;
3225 surface
->overlay_destrect
.top
= 0;
3226 surface
->overlay_destrect
.right
= dst_surface
? dst_surface
->resource
.width
: 0;
3227 surface
->overlay_destrect
.bottom
= dst_surface
? dst_surface
->resource
.height
: 0;
3230 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
3232 list_remove(&surface
->overlay_entry
);
3235 if (flags
& WINEDDOVER_SHOW
)
3237 if (surface
->overlay_dest
!= dst_surface
)
3239 surface
->overlay_dest
= dst_surface
;
3240 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
3243 else if (flags
& WINEDDOVER_HIDE
)
3245 /* tests show that the rectangles are erased on hide */
3246 surface
->overlay_srcrect
.left
= 0; surface
->overlay_srcrect
.top
= 0;
3247 surface
->overlay_srcrect
.right
= 0; surface
->overlay_srcrect
.bottom
= 0;
3248 surface
->overlay_destrect
.left
= 0; surface
->overlay_destrect
.top
= 0;
3249 surface
->overlay_destrect
.right
= 0; surface
->overlay_destrect
.bottom
= 0;
3250 surface
->overlay_dest
= NULL
;
3253 surface
->surface_ops
->surface_draw_overlay(surface
);
3258 HRESULT CDECL
wined3d_surface_set_clipper(struct wined3d_surface
*surface
, struct wined3d_clipper
*clipper
)
3260 TRACE("surface %p, clipper %p.\n", surface
, clipper
);
3262 surface
->clipper
= clipper
;
3267 struct wined3d_clipper
* CDECL
wined3d_surface_get_clipper(const struct wined3d_surface
*surface
)
3269 TRACE("surface %p.\n", surface
);
3271 return surface
->clipper
;
3274 HRESULT CDECL
wined3d_surface_set_format(struct wined3d_surface
*surface
, enum wined3d_format_id format_id
)
3276 const struct wined3d_format
*format
= wined3d_get_format(&surface
->resource
.device
->adapter
->gl_info
, format_id
);
3278 TRACE("surface %p, format %s.\n", surface
, debug_d3dformat(format_id
));
3280 if (surface
->resource
.format
->id
!= WINED3DFMT_UNKNOWN
)
3282 FIXME("The format of the surface must be WINED3DFORMAT_UNKNOWN.\n");
3283 return WINED3DERR_INVALIDCALL
;
3286 surface
->resource
.size
= wined3d_format_calculate_size(format
, surface
->resource
.device
->surface_alignment
,
3287 surface
->pow2Width
, surface
->pow2Height
);
3288 surface
->flags
|= (WINED3DFMT_D16_LOCKABLE
== format_id
) ? SFLAG_LOCKABLE
: 0;
3289 surface
->resource
.format
= format
;
3291 TRACE("size %u, byte_count %u\n", surface
->resource
.size
, format
->byte_count
);
3292 TRACE("glFormat %#x, glInternal %#x, glType %#x.\n",
3293 format
->glFormat
, format
->glInternal
, format
->glType
);
3298 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
3299 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3301 unsigned short *dst_s
;
3305 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3307 for (y
= 0; y
< h
; ++y
)
3309 src_f
= (const float *)(src
+ y
* pitch_in
);
3310 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
3311 for (x
= 0; x
< w
; ++x
)
3313 dst_s
[x
] = float_32_to_16(src_f
+ x
);
3318 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3319 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3321 static const unsigned char convert_5to8
[] =
3323 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3324 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3325 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3326 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3328 static const unsigned char convert_6to8
[] =
3330 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3331 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3332 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3333 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3334 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3335 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3336 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3337 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3341 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3343 for (y
= 0; y
< h
; ++y
)
3345 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
3346 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3347 for (x
= 0; x
< w
; ++x
)
3349 WORD pixel
= src_line
[x
];
3350 dst_line
[x
] = 0xff000000
3351 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
3352 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
3353 | convert_5to8
[(pixel
& 0x001f)];
3358 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3359 * in both cases we're just setting the X / Alpha channel to 0xff. */
3360 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3361 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3365 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3367 for (y
= 0; y
< h
; ++y
)
3369 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
3370 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3372 for (x
= 0; x
< w
; ++x
)
3374 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
3379 static inline BYTE
cliptobyte(int x
)
3381 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
3384 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3385 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3387 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
3390 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3392 for (y
= 0; y
< h
; ++y
)
3394 const BYTE
*src_line
= src
+ y
* pitch_in
;
3395 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3396 for (x
= 0; x
< w
; ++x
)
3398 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3399 * C = Y - 16; D = U - 128; E = V - 128;
3400 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3401 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3402 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3403 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3404 * U and V are shared between the pixels. */
3405 if (!(x
& 1)) /* For every even pixel, read new U and V. */
3407 d
= (int) src_line
[1] - 128;
3408 e
= (int) src_line
[3] - 128;
3410 g2
= - 100 * d
- 208 * e
+ 128;
3413 c2
= 298 * ((int) src_line
[0] - 16);
3414 dst_line
[x
] = 0xff000000
3415 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
3416 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
3417 | cliptobyte((c2
+ b2
) >> 8); /* blue */
3418 /* Scale RGB values to 0..255 range,
3419 * then clip them if still not in range (may be negative),
3420 * then shift them within DWORD if necessary. */
3426 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
3427 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3430 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
3432 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
3434 for (y
= 0; y
< h
; ++y
)
3436 const BYTE
*src_line
= src
+ y
* pitch_in
;
3437 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
3438 for (x
= 0; x
< w
; ++x
)
3440 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3441 * C = Y - 16; D = U - 128; E = V - 128;
3442 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3443 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3444 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3445 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3446 * U and V are shared between the pixels. */
3447 if (!(x
& 1)) /* For every even pixel, read new U and V. */
3449 d
= (int) src_line
[1] - 128;
3450 e
= (int) src_line
[3] - 128;
3452 g2
= - 100 * d
- 208 * e
+ 128;
3455 c2
= 298 * ((int) src_line
[0] - 16);
3456 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
3457 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
3458 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
3459 /* Scale RGB values to 0..255 range,
3460 * then clip them if still not in range (may be negative),
3461 * then shift them within DWORD if necessary. */
3467 struct d3dfmt_convertor_desc
3469 enum wined3d_format_id from
, to
;
3470 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
3473 static const struct d3dfmt_convertor_desc convertors
[] =
3475 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
3476 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
3477 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
3478 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
3479 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
3480 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
3483 static inline const struct d3dfmt_convertor_desc
*find_convertor(enum wined3d_format_id from
,
3484 enum wined3d_format_id to
)
3488 for (i
= 0; i
< (sizeof(convertors
) / sizeof(*convertors
)); ++i
)
3490 if (convertors
[i
].from
== from
&& convertors
[i
].to
== to
)
3491 return &convertors
[i
];
3497 /*****************************************************************************
3498 * surface_convert_format
3500 * Creates a duplicate of a surface in a different format. Is used by Blt to
3501 * blit between surfaces with different formats.
3504 * source: Source surface
3505 * fmt: Requested destination format
3507 *****************************************************************************/
3508 static struct wined3d_surface
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
3510 const struct d3dfmt_convertor_desc
*conv
;
3511 WINED3DLOCKED_RECT lock_src
, lock_dst
;
3512 struct wined3d_surface
*ret
= NULL
;
3515 conv
= find_convertor(source
->resource
.format
->id
, to_fmt
);
3518 FIXME("Cannot find a conversion function from format %s to %s.\n",
3519 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
3523 wined3d_surface_create(source
->resource
.device
, source
->resource
.width
,
3524 source
->resource
.height
, to_fmt
, TRUE
/* lockable */, TRUE
/* discard */, 0 /* level */,
3525 0 /* usage */, WINED3DPOOL_SCRATCH
, WINED3DMULTISAMPLE_NONE
/* TODO: Multisampled conversion */,
3526 0 /* MultiSampleQuality */, source
->surface_type
, NULL
/* parent */, &wined3d_null_parent_ops
, &ret
);
3529 ERR("Failed to create a destination surface for conversion.\n");
3533 memset(&lock_src
, 0, sizeof(lock_src
));
3534 memset(&lock_dst
, 0, sizeof(lock_dst
));
3536 hr
= wined3d_surface_map(source
, &lock_src
, NULL
, WINED3DLOCK_READONLY
);
3539 ERR("Failed to lock the source surface.\n");
3540 wined3d_surface_decref(ret
);
3543 hr
= wined3d_surface_map(ret
, &lock_dst
, NULL
, WINED3DLOCK_READONLY
);
3546 ERR("Failed to lock the destination surface.\n");
3547 wined3d_surface_unmap(source
);
3548 wined3d_surface_decref(ret
);
3552 conv
->convert(lock_src
.pBits
, lock_dst
.pBits
, lock_src
.Pitch
, lock_dst
.Pitch
,
3553 source
->resource
.width
, source
->resource
.height
);
3555 wined3d_surface_unmap(ret
);
3556 wined3d_surface_unmap(source
);
3561 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
3562 unsigned int bpp
, UINT pitch
, DWORD color
)
3569 #define COLORFILL_ROW(type) \
3571 type *d = (type *)buf; \
3572 for (x = 0; x < width; ++x) \
3573 d[x] = (type)color; \
3579 COLORFILL_ROW(BYTE
);
3583 COLORFILL_ROW(WORD
);
3589 for (x
= 0; x
< width
; ++x
, d
+= 3)
3591 d
[0] = (color
) & 0xFF;
3592 d
[1] = (color
>> 8) & 0xFF;
3593 d
[2] = (color
>> 16) & 0xFF;
3598 COLORFILL_ROW(DWORD
);
3602 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
3603 return WINED3DERR_NOTAVAILABLE
;
3606 #undef COLORFILL_ROW
3608 /* Now copy first row. */
3610 for (y
= 1; y
< height
; ++y
)
3613 memcpy(buf
, first
, width
* bpp
);
3619 HRESULT CDECL
wined3d_surface_unmap(struct wined3d_surface
*surface
)
3621 TRACE("surface %p.\n", surface
);
3623 if (!(surface
->flags
& SFLAG_LOCKED
))
3625 WARN("Trying to unmap unmapped surface.\n");
3626 return WINEDDERR_NOTLOCKED
;
3628 surface
->flags
&= ~SFLAG_LOCKED
;
3630 surface
->surface_ops
->surface_unmap(surface
);
3635 HRESULT CDECL
wined3d_surface_map(struct wined3d_surface
*surface
,
3636 WINED3DLOCKED_RECT
*locked_rect
, const RECT
*rect
, DWORD flags
)
3638 TRACE("surface %p, locked_rect %p, rect %s, flags %#x.\n",
3639 surface
, locked_rect
, wine_dbgstr_rect(rect
), flags
);
3641 if (surface
->flags
& SFLAG_LOCKED
)
3643 WARN("Surface is already mapped.\n");
3644 return WINED3DERR_INVALIDCALL
;
3646 surface
->flags
|= SFLAG_LOCKED
;
3648 if (!(surface
->flags
& SFLAG_LOCKABLE
))
3649 WARN("Trying to lock unlockable surface.\n");
3651 surface
->surface_ops
->surface_map(surface
, rect
, flags
);
3653 locked_rect
->Pitch
= wined3d_surface_get_pitch(surface
);
3657 locked_rect
->pBits
= surface
->resource
.allocatedMemory
;
3658 surface
->lockedRect
.left
= 0;
3659 surface
->lockedRect
.top
= 0;
3660 surface
->lockedRect
.right
= surface
->resource
.width
;
3661 surface
->lockedRect
.bottom
= surface
->resource
.height
;
3665 const struct wined3d_format
*format
= surface
->resource
.format
;
3667 if ((format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_COMPRESSED
)
3669 /* Compressed textures are block based, so calculate the offset of
3670 * the block that contains the top-left pixel of the locked rectangle. */
3671 locked_rect
->pBits
= surface
->resource
.allocatedMemory
3672 + ((rect
->top
/ format
->block_height
) * locked_rect
->Pitch
)
3673 + ((rect
->left
/ format
->block_width
) * format
->block_byte_count
);
3677 locked_rect
->pBits
= surface
->resource
.allocatedMemory
3678 + (locked_rect
->Pitch
* rect
->top
)
3679 + (rect
->left
* format
->byte_count
);
3681 surface
->lockedRect
.left
= rect
->left
;
3682 surface
->lockedRect
.top
= rect
->top
;
3683 surface
->lockedRect
.right
= rect
->right
;
3684 surface
->lockedRect
.bottom
= rect
->bottom
;
3687 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
3688 TRACE("Returning memory %p, pitch %u.\n", locked_rect
->pBits
, locked_rect
->Pitch
);
3693 HRESULT CDECL
wined3d_surface_getdc(struct wined3d_surface
*surface
, HDC
*dc
)
3697 TRACE("surface %p, dc %p.\n", surface
, dc
);
3699 if (surface
->flags
& SFLAG_USERPTR
)
3701 ERR("Not supported on surfaces with application-provided memory.\n");
3702 return WINEDDERR_NODC
;
3705 /* Give more detailed info for ddraw. */
3706 if (surface
->flags
& SFLAG_DCINUSE
)
3707 return WINEDDERR_DCALREADYCREATED
;
3709 /* Can't GetDC if the surface is locked. */
3710 if (surface
->flags
& SFLAG_LOCKED
)
3711 return WINED3DERR_INVALIDCALL
;
3713 hr
= surface
->surface_ops
->surface_getdc(surface
);
3717 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3718 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
3720 /* GetDC on palettized formats is unsupported in D3D9, and the method
3721 * is missing in D3D8, so this should only be used for DX <=7
3722 * surfaces (with non-device palettes). */
3723 const PALETTEENTRY
*pal
= NULL
;
3725 if (surface
->palette
)
3727 pal
= surface
->palette
->palents
;
3731 struct wined3d_swapchain
*swapchain
= surface
->resource
.device
->swapchains
[0];
3732 struct wined3d_surface
*dds_primary
= swapchain
->front_buffer
;
3734 if (dds_primary
&& dds_primary
->palette
)
3735 pal
= dds_primary
->palette
->palents
;
3743 for (i
= 0; i
< 256; ++i
)
3745 col
[i
].rgbRed
= pal
[i
].peRed
;
3746 col
[i
].rgbGreen
= pal
[i
].peGreen
;
3747 col
[i
].rgbBlue
= pal
[i
].peBlue
;
3748 col
[i
].rgbReserved
= 0;
3750 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
3754 surface
->flags
|= SFLAG_DCINUSE
;
3757 TRACE("Returning dc %p.\n", *dc
);
3762 HRESULT CDECL
wined3d_surface_releasedc(struct wined3d_surface
*surface
, HDC dc
)
3764 TRACE("surface %p, dc %p.\n", surface
, dc
);
3766 if (!(surface
->flags
& SFLAG_DCINUSE
))
3767 return WINEDDERR_NODC
;
3769 if (surface
->hDC
!= dc
)
3771 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
3773 return WINEDDERR_NODC
;
3776 if ((surface
->flags
& SFLAG_PBO
) && surface
->resource
.allocatedMemory
)
3778 /* Copy the contents of the DIB over to the PBO. */
3779 memcpy(surface
->resource
.allocatedMemory
, surface
->dib
.bitmap_data
, surface
->dib
.bitmap_size
);
3782 /* We locked first, so unlock now. */
3783 wined3d_surface_unmap(surface
);
3785 surface
->flags
&= ~SFLAG_DCINUSE
;
3790 HRESULT CDECL
wined3d_surface_flip(struct wined3d_surface
*surface
, struct wined3d_surface
*override
, DWORD flags
)
3792 struct wined3d_swapchain
*swapchain
;
3795 TRACE("surface %p, override %p, flags %#x.\n", surface
, override
, flags
);
3797 if (surface
->container
.type
!= WINED3D_CONTAINER_SWAPCHAIN
)
3799 ERR("Flipped surface is not on a swapchain.\n");
3800 return WINEDDERR_NOTFLIPPABLE
;
3802 swapchain
= surface
->container
.u
.swapchain
;
3804 hr
= surface
->surface_ops
->surface_flip(surface
, override
);
3808 /* Just overwrite the swapchain presentation interval. This is ok because
3809 * only ddraw apps can call Flip, and only d3d8 and d3d9 applications
3810 * specify the presentation interval. */
3811 if (!(flags
& (WINEDDFLIP_NOVSYNC
| WINEDDFLIP_INTERVAL2
| WINEDDFLIP_INTERVAL3
| WINEDDFLIP_INTERVAL4
)))
3812 swapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_ONE
;
3813 else if (flags
& WINEDDFLIP_NOVSYNC
)
3814 swapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_IMMEDIATE
;
3815 else if (flags
& WINEDDFLIP_INTERVAL2
)
3816 swapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_TWO
;
3817 else if (flags
& WINEDDFLIP_INTERVAL3
)
3818 swapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_THREE
;
3820 swapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_FOUR
;
3822 return wined3d_swapchain_present(swapchain
, NULL
, NULL
, swapchain
->win_handle
, NULL
, 0);
3825 /* Do not call while under the GL lock. */
3826 void surface_internal_preload(struct wined3d_surface
*surface
, enum WINED3DSRGB srgb
)
3828 struct wined3d_device
*device
= surface
->resource
.device
;
3830 TRACE("iface %p, srgb %#x.\n", surface
, srgb
);
3832 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
3834 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
3836 TRACE("Passing to container (%p).\n", texture
);
3837 texture
->texture_ops
->texture_preload(texture
, srgb
);
3841 struct wined3d_context
*context
= NULL
;
3843 TRACE("(%p) : About to load surface\n", surface
);
3845 if (!device
->isInDraw
) context
= context_acquire(device
, NULL
);
3847 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3848 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
3850 if (palette9_changed(surface
))
3852 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
3853 /* TODO: This is not necessarily needed with hw palettized texture support */
3854 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
3855 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
3856 surface_modify_location(surface
, SFLAG_INTEXTURE
, FALSE
);
3860 surface_load(surface
, srgb
== SRGB_SRGB
? TRUE
: FALSE
);
3862 if (surface
->resource
.pool
== WINED3DPOOL_DEFAULT
)
3864 /* Tell opengl to try and keep this texture in video ram (well mostly) */
3868 glPrioritizeTextures(1, &surface
->texture_name
, &tmp
);
3872 if (context
) context_release(context
);
3876 BOOL
surface_init_sysmem(struct wined3d_surface
*surface
)
3878 if (!surface
->resource
.allocatedMemory
)
3880 surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
3881 surface
->resource
.size
+ RESOURCE_ALIGNMENT
);
3882 if (!surface
->resource
.heapMemory
)
3884 ERR("Out of memory\n");
3887 surface
->resource
.allocatedMemory
=
3888 (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
+ (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
3892 memset(surface
->resource
.allocatedMemory
, 0, surface
->resource
.size
);
3895 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
3900 /* Read the framebuffer back into the surface */
3901 static void read_from_framebuffer(struct wined3d_surface
*surface
, const RECT
*rect
, void *dest
, UINT pitch
)
3903 struct wined3d_device
*device
= surface
->resource
.device
;
3904 const struct wined3d_gl_info
*gl_info
;
3905 struct wined3d_context
*context
;
3909 BYTE
*row
, *top
, *bottom
;
3913 BOOL srcIsUpsideDown
;
3918 if(wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
) {
3919 static BOOL warned
= FALSE
;
3921 ERR("The application tries to lock the render target, but render target locking is disabled\n");
3927 context
= context_acquire(device
, surface
);
3928 context_apply_blit_state(context
, device
);
3929 gl_info
= context
->gl_info
;
3933 /* Select the correct read buffer, and give some debug output.
3934 * There is no need to keep track of the current read buffer or reset it, every part of the code
3935 * that reads sets the read buffer as desired.
3937 if (surface_is_offscreen(surface
))
3939 /* Mapping the primary render target which is not on a swapchain.
3940 * Read from the back buffer. */
3941 TRACE("Mapping offscreen render target.\n");
3942 glReadBuffer(device
->offscreenBuffer
);
3943 srcIsUpsideDown
= TRUE
;
3947 /* Onscreen surfaces are always part of a swapchain */
3948 GLenum buffer
= surface_get_gl_buffer(surface
);
3949 TRACE("Mapping %#x buffer.\n", buffer
);
3950 glReadBuffer(buffer
);
3951 checkGLcall("glReadBuffer");
3952 srcIsUpsideDown
= FALSE
;
3955 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
3958 local_rect
.left
= 0;
3960 local_rect
.right
= surface
->resource
.width
;
3961 local_rect
.bottom
= surface
->resource
.height
;
3967 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
3969 switch (surface
->resource
.format
->id
)
3971 case WINED3DFMT_P8_UINT
:
3973 if (primary_render_target_is_p8(device
))
3975 /* In case of P8 render targets the index is stored in the alpha component */
3977 type
= GL_UNSIGNED_BYTE
;
3979 bpp
= surface
->resource
.format
->byte_count
;
3983 /* GL can't return palettized data, so read ARGB pixels into a
3984 * separate block of memory and convert them into palettized format
3985 * in software. Slow, but if the app means to use palettized render
3986 * targets and locks it...
3988 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
3989 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
3990 * for the color channels when palettizing the colors.
3993 type
= GL_UNSIGNED_BYTE
;
3995 mem
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
* 3);
3998 ERR("Out of memory\n");
4002 bpp
= surface
->resource
.format
->byte_count
* 3;
4009 fmt
= surface
->resource
.format
->glFormat
;
4010 type
= surface
->resource
.format
->glType
;
4011 bpp
= surface
->resource
.format
->byte_count
;
4014 if (surface
->flags
& SFLAG_PBO
)
4016 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
4017 checkGLcall("glBindBufferARB");
4020 ERR("mem not null for pbo -- unexpected\n");
4025 /* Save old pixel store pack state */
4026 glGetIntegerv(GL_PACK_ROW_LENGTH
, &rowLen
);
4027 checkGLcall("glGetIntegerv");
4028 glGetIntegerv(GL_PACK_SKIP_PIXELS
, &skipPix
);
4029 checkGLcall("glGetIntegerv");
4030 glGetIntegerv(GL_PACK_SKIP_ROWS
, &skipRow
);
4031 checkGLcall("glGetIntegerv");
4033 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4034 glPixelStorei(GL_PACK_ROW_LENGTH
, surface
->resource
.width
);
4035 checkGLcall("glPixelStorei");
4036 glPixelStorei(GL_PACK_SKIP_PIXELS
, local_rect
.left
);
4037 checkGLcall("glPixelStorei");
4038 glPixelStorei(GL_PACK_SKIP_ROWS
, local_rect
.top
);
4039 checkGLcall("glPixelStorei");
4041 glReadPixels(local_rect
.left
, !srcIsUpsideDown
? (surface
->resource
.height
- local_rect
.bottom
) : local_rect
.top
,
4042 local_rect
.right
- local_rect
.left
,
4043 local_rect
.bottom
- local_rect
.top
,
4045 checkGLcall("glReadPixels");
4047 /* Reset previous pixel store pack state */
4048 glPixelStorei(GL_PACK_ROW_LENGTH
, rowLen
);
4049 checkGLcall("glPixelStorei");
4050 glPixelStorei(GL_PACK_SKIP_PIXELS
, skipPix
);
4051 checkGLcall("glPixelStorei");
4052 glPixelStorei(GL_PACK_SKIP_ROWS
, skipRow
);
4053 checkGLcall("glPixelStorei");
4055 if (surface
->flags
& SFLAG_PBO
)
4057 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
4058 checkGLcall("glBindBufferARB");
4060 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4061 * to get a pointer to it and perform the flipping in software. This is a lot
4062 * faster than calling glReadPixels for each line. In case we want more speed
4063 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4064 if (!srcIsUpsideDown
)
4066 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
4067 checkGLcall("glBindBufferARB");
4069 mem
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
4070 checkGLcall("glMapBufferARB");
4074 /* TODO: Merge this with the palettization loop below for P8 targets */
4075 if(!srcIsUpsideDown
) {
4077 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4078 Flip the lines in software */
4079 len
= (local_rect
.right
- local_rect
.left
) * bpp
;
4080 off
= local_rect
.left
* bpp
;
4082 row
= HeapAlloc(GetProcessHeap(), 0, len
);
4084 ERR("Out of memory\n");
4085 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
4086 HeapFree(GetProcessHeap(), 0, mem
);
4091 top
= mem
+ pitch
* local_rect
.top
;
4092 bottom
= mem
+ pitch
* (local_rect
.bottom
- 1);
4093 for(i
= 0; i
< (local_rect
.bottom
- local_rect
.top
) / 2; i
++) {
4094 memcpy(row
, top
+ off
, len
);
4095 memcpy(top
+ off
, bottom
+ off
, len
);
4096 memcpy(bottom
+ off
, row
, len
);
4100 HeapFree(GetProcessHeap(), 0, row
);
4102 /* Unmap the temp PBO buffer */
4103 if (surface
->flags
& SFLAG_PBO
)
4105 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
4106 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4111 context_release(context
);
4113 /* For P8 textures we need to perform an inverse palette lookup. This is
4114 * done by searching for a palette index which matches the RGB value.
4115 * Note this isn't guaranteed to work when there are multiple entries for
4116 * the same color but we have no choice. In case of P8 render targets,
4117 * the index is stored in the alpha component so no conversion is needed. */
4118 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
&& !primary_render_target_is_p8(device
))
4120 const PALETTEENTRY
*pal
= NULL
;
4121 DWORD width
= pitch
/ 3;
4124 if (surface
->palette
)
4126 pal
= surface
->palette
->palents
;
4130 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4131 HeapFree(GetProcessHeap(), 0, mem
);
4135 for(y
= local_rect
.top
; y
< local_rect
.bottom
; y
++) {
4136 for(x
= local_rect
.left
; x
< local_rect
.right
; x
++) {
4137 /* start lines pixels */
4138 const BYTE
*blue
= mem
+ y
* pitch
+ x
* (sizeof(BYTE
) * 3);
4139 const BYTE
*green
= blue
+ 1;
4140 const BYTE
*red
= green
+ 1;
4142 for(c
= 0; c
< 256; c
++) {
4143 if(*red
== pal
[c
].peRed
&&
4144 *green
== pal
[c
].peGreen
&&
4145 *blue
== pal
[c
].peBlue
)
4147 *((BYTE
*) dest
+ y
* width
+ x
) = c
;
4153 HeapFree(GetProcessHeap(), 0, mem
);
4157 /* Read the framebuffer contents into a texture */
4158 static void read_from_framebuffer_texture(struct wined3d_surface
*surface
, BOOL srgb
)
4160 struct wined3d_device
*device
= surface
->resource
.device
;
4161 const struct wined3d_gl_info
*gl_info
;
4162 struct wined3d_context
*context
;
4164 if (!surface_is_offscreen(surface
))
4166 /* We would need to flip onscreen surfaces, but there's no efficient
4167 * way to do that here. It makes more sense for the caller to
4168 * explicitly go through sysmem. */
4169 ERR("Not supported for onscreen targets.\n");
4173 /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
4174 * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
4175 * states in the stateblock, and no driver was found yet that had bugs in that regard.
4177 context
= context_acquire(device
, surface
);
4178 gl_info
= context
->gl_info
;
4179 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
4181 surface_prepare_texture(surface
, gl_info
, srgb
);
4182 surface_bind_and_dirtify(surface
, gl_info
, srgb
);
4184 TRACE("Reading back offscreen render target %p.\n", surface
);
4188 glReadBuffer(device
->offscreenBuffer
);
4189 checkGLcall("glReadBuffer");
4191 glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
4192 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
4193 checkGLcall("glCopyTexSubImage2D");
4197 context_release(context
);
4200 /* Context activation is done by the caller. */
4201 static void surface_prepare_texture_internal(struct wined3d_surface
*surface
,
4202 const struct wined3d_gl_info
*gl_info
, BOOL srgb
)
4204 DWORD alloc_flag
= srgb
? SFLAG_SRGBALLOCATED
: SFLAG_ALLOCATED
;
4205 CONVERT_TYPES convert
;
4206 struct wined3d_format format
;
4208 if (surface
->flags
& alloc_flag
) return;
4210 d3dfmt_get_conv(surface
, TRUE
, TRUE
, &format
, &convert
);
4211 if (convert
!= NO_CONVERSION
|| format
.convert
) surface
->flags
|= SFLAG_CONVERTED
;
4212 else surface
->flags
&= ~SFLAG_CONVERTED
;
4214 surface_bind_and_dirtify(surface
, gl_info
, srgb
);
4215 surface_allocate_surface(surface
, gl_info
, &format
, srgb
);
4216 surface
->flags
|= alloc_flag
;
4219 /* Context activation is done by the caller. */
4220 void surface_prepare_texture(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL srgb
)
4222 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
4224 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
4225 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
4228 TRACE("surface %p is a subresource of texture %p.\n", surface
, texture
);
4230 for (i
= 0; i
< sub_count
; ++i
)
4232 struct wined3d_surface
*s
= surface_from_resource(texture
->sub_resources
[i
]);
4233 surface_prepare_texture_internal(s
, gl_info
, srgb
);
4239 surface_prepare_texture_internal(surface
, gl_info
, srgb
);
4242 static void flush_to_framebuffer_drawpixels(struct wined3d_surface
*surface
,
4243 const RECT
*rect
, GLenum fmt
, GLenum type
, UINT bpp
, const BYTE
*mem
)
4245 struct wined3d_device
*device
= surface
->resource
.device
;
4246 UINT pitch
= wined3d_surface_get_pitch(surface
);
4247 const struct wined3d_gl_info
*gl_info
;
4248 struct wined3d_context
*context
;
4252 surface_get_rect(surface
, rect
, &local_rect
);
4254 mem
+= local_rect
.top
* pitch
+ local_rect
.left
* bpp
;
4255 w
= local_rect
.right
- local_rect
.left
;
4256 h
= local_rect
.bottom
- local_rect
.top
;
4258 /* Activate the correct context for the render target */
4259 context
= context_acquire(device
, surface
);
4260 context_apply_blit_state(context
, device
);
4261 gl_info
= context
->gl_info
;
4265 if (!surface_is_offscreen(surface
))
4267 GLenum buffer
= surface_get_gl_buffer(surface
);
4268 TRACE("Unlocking %#x buffer.\n", buffer
);
4269 context_set_draw_buffer(context
, buffer
);
4271 surface_translate_drawable_coords(surface
, context
->win_handle
, &local_rect
);
4272 glPixelZoom(1.0f
, -1.0f
);
4276 /* Primary offscreen render target */
4277 TRACE("Offscreen render target.\n");
4278 context_set_draw_buffer(context
, device
->offscreenBuffer
);
4280 glPixelZoom(1.0f
, 1.0f
);
4283 glRasterPos3i(local_rect
.left
, local_rect
.top
, 1);
4284 checkGLcall("glRasterPos3i");
4286 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4287 glPixelStorei(GL_UNPACK_ROW_LENGTH
, surface
->resource
.width
);
4289 if (surface
->flags
& SFLAG_PBO
)
4291 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
4292 checkGLcall("glBindBufferARB");
4295 glDrawPixels(w
, h
, fmt
, type
, mem
);
4296 checkGLcall("glDrawPixels");
4298 if (surface
->flags
& SFLAG_PBO
)
4300 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4301 checkGLcall("glBindBufferARB");
4304 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
4305 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4309 if (wined3d_settings
.strict_draw_ordering
4310 || (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
4311 && surface
->container
.u
.swapchain
->front_buffer
== surface
))
4314 context_release(context
);
4317 HRESULT
d3dfmt_get_conv(const struct wined3d_surface
*surface
, BOOL need_alpha_ck
,
4318 BOOL use_texturing
, struct wined3d_format
*format
, CONVERT_TYPES
*convert
)
4320 BOOL colorkey_active
= need_alpha_ck
&& (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
);
4321 const struct wined3d_device
*device
= surface
->resource
.device
;
4322 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4323 BOOL blit_supported
= FALSE
;
4325 /* Copy the default values from the surface. Below we might perform fixups */
4326 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
4327 *format
= *surface
->resource
.format
;
4328 *convert
= NO_CONVERSION
;
4330 /* Ok, now look if we have to do any conversion */
4331 switch (surface
->resource
.format
->id
)
4333 case WINED3DFMT_P8_UINT
:
4334 /* Below the call to blit_supported is disabled for Wine 1.2
4335 * because the function isn't operating correctly yet. At the
4336 * moment 8-bit blits are handled in software and if certain GL
4337 * extensions are around, surface conversion is performed at
4338 * upload time. The blit_supported call recognizes it as a
4339 * destination fixup. This type of upload 'fixup' and 8-bit to
4340 * 8-bit blits need to be handled by the blit_shader.
4341 * TODO: get rid of this #if 0. */
4343 blit_supported
= device
->blitter
->blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4344 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4345 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
);
4347 blit_supported
= gl_info
->supported
[EXT_PALETTED_TEXTURE
] || gl_info
->supported
[ARB_FRAGMENT_PROGRAM
];
4349 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
4350 * texturing. Further also use conversion in case of color keying.
4351 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
4352 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
4353 * conflicts with this.
4355 if (!((blit_supported
&& device
->fb
.render_targets
&& surface
== device
->fb
.render_targets
[0]))
4356 || colorkey_active
|| !use_texturing
)
4358 format
->glFormat
= GL_RGBA
;
4359 format
->glInternal
= GL_RGBA
;
4360 format
->glType
= GL_UNSIGNED_BYTE
;
4361 format
->conv_byte_count
= 4;
4362 if (colorkey_active
)
4363 *convert
= CONVERT_PALETTED_CK
;
4365 *convert
= CONVERT_PALETTED
;
4369 case WINED3DFMT_B2G3R3_UNORM
:
4370 /* **********************
4371 GL_UNSIGNED_BYTE_3_3_2
4372 ********************** */
4373 if (colorkey_active
) {
4374 /* This texture format will never be used.. So do not care about color keying
4375 up until the point in time it will be needed :-) */
4376 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
4380 case WINED3DFMT_B5G6R5_UNORM
:
4381 if (colorkey_active
)
4383 *convert
= CONVERT_CK_565
;
4384 format
->glFormat
= GL_RGBA
;
4385 format
->glInternal
= GL_RGB5_A1
;
4386 format
->glType
= GL_UNSIGNED_SHORT_5_5_5_1
;
4387 format
->conv_byte_count
= 2;
4391 case WINED3DFMT_B5G5R5X1_UNORM
:
4392 if (colorkey_active
)
4394 *convert
= CONVERT_CK_5551
;
4395 format
->glFormat
= GL_BGRA
;
4396 format
->glInternal
= GL_RGB5_A1
;
4397 format
->glType
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
4398 format
->conv_byte_count
= 2;
4402 case WINED3DFMT_B8G8R8_UNORM
:
4403 if (colorkey_active
)
4405 *convert
= CONVERT_CK_RGB24
;
4406 format
->glFormat
= GL_RGBA
;
4407 format
->glInternal
= GL_RGBA8
;
4408 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
4409 format
->conv_byte_count
= 4;
4413 case WINED3DFMT_B8G8R8X8_UNORM
:
4414 if (colorkey_active
)
4416 *convert
= CONVERT_RGB32_888
;
4417 format
->glFormat
= GL_RGBA
;
4418 format
->glInternal
= GL_RGBA8
;
4419 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
4420 format
->conv_byte_count
= 4;
4431 void d3dfmt_p8_init_palette(const struct wined3d_surface
*surface
, BYTE table
[256][4], BOOL colorkey
)
4433 const struct wined3d_device
*device
= surface
->resource
.device
;
4434 const struct wined3d_palette
*pal
= surface
->palette
;
4435 BOOL index_in_alpha
= FALSE
;
4438 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4439 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4440 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4441 * duplicate entries. Store the color key in the unused alpha component to speed the
4442 * download up and to make conversion unneeded. */
4443 index_in_alpha
= primary_render_target_is_p8(device
);
4447 /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
4448 if (device
->wined3d
->flags
& WINED3D_PALETTE_PER_SURFACE
)
4450 ERR("This code should never get entered for DirectDraw!, expect problems\n");
4453 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4454 * there's no palette at this time. */
4455 for (i
= 0; i
< 256; i
++) table
[i
][3] = i
;
4460 /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
4461 * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
4462 * capability flag is present (wine does advertise this capability) */
4463 for (i
= 0; i
< 256; ++i
)
4465 table
[i
][0] = device
->palettes
[device
->currentPalette
][i
].peRed
;
4466 table
[i
][1] = device
->palettes
[device
->currentPalette
][i
].peGreen
;
4467 table
[i
][2] = device
->palettes
[device
->currentPalette
][i
].peBlue
;
4468 table
[i
][3] = device
->palettes
[device
->currentPalette
][i
].peFlags
;
4474 TRACE("Using surface palette %p\n", pal
);
4475 /* Get the surface's palette */
4476 for (i
= 0; i
< 256; ++i
)
4478 table
[i
][0] = pal
->palents
[i
].peRed
;
4479 table
[i
][1] = pal
->palents
[i
].peGreen
;
4480 table
[i
][2] = pal
->palents
[i
].peBlue
;
4482 /* When index_in_alpha is set the palette index is stored in the
4483 * alpha component. In case of a readback we can then read
4484 * GL_ALPHA. Color keying is handled in BltOverride using a
4485 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4486 * color key itself is passed to glAlphaFunc in other cases the
4487 * alpha component of pixels that should be masked away is set to 0. */
4492 else if (colorkey
&& (i
>= surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4493 && (i
<= surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4497 else if (pal
->flags
& WINEDDPCAPS_ALPHA
)
4499 table
[i
][3] = pal
->palents
[i
].peFlags
;
4509 static HRESULT
d3dfmt_convert_surface(const BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
,
4510 UINT height
, UINT outpitch
, CONVERT_TYPES convert
, struct wined3d_surface
*surface
)
4514 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src
, dst
, pitch
, height
, outpitch
, convert
, surface
);
4519 memcpy(dst
, src
, pitch
* height
);
4522 case CONVERT_PALETTED
:
4523 case CONVERT_PALETTED_CK
:
4528 d3dfmt_p8_init_palette(surface
, table
, (convert
== CONVERT_PALETTED_CK
));
4530 for (y
= 0; y
< height
; y
++)
4532 source
= src
+ pitch
* y
;
4533 dest
= dst
+ outpitch
* y
;
4534 /* This is an 1 bpp format, using the width here is fine */
4535 for (x
= 0; x
< width
; x
++) {
4536 BYTE color
= *source
++;
4537 *dest
++ = table
[color
][0];
4538 *dest
++ = table
[color
][1];
4539 *dest
++ = table
[color
][2];
4540 *dest
++ = table
[color
][3];
4546 case CONVERT_CK_565
:
4548 /* Converting the 565 format in 5551 packed to emulate color-keying.
4550 Note : in all these conversion, it would be best to average the averaging
4551 pixels to get the color of the pixel that will be color-keyed to
4552 prevent 'color bleeding'. This will be done later on if ever it is
4555 Note2: Nvidia documents say that their driver does not support alpha + color keying
4556 on the same surface and disables color keying in such a case
4562 TRACE("Color keyed 565\n");
4564 for (y
= 0; y
< height
; y
++) {
4565 Source
= (const WORD
*)(src
+ y
* pitch
);
4566 Dest
= (WORD
*) (dst
+ y
* outpitch
);
4567 for (x
= 0; x
< width
; x
++ ) {
4568 WORD color
= *Source
++;
4569 *Dest
= ((color
& 0xFFC0) | ((color
& 0x1F) << 1));
4570 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4571 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4579 case CONVERT_CK_5551
:
4581 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4585 TRACE("Color keyed 5551\n");
4586 for (y
= 0; y
< height
; y
++) {
4587 Source
= (const WORD
*)(src
+ y
* pitch
);
4588 Dest
= (WORD
*) (dst
+ y
* outpitch
);
4589 for (x
= 0; x
< width
; x
++ ) {
4590 WORD color
= *Source
++;
4592 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4593 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4596 *Dest
&= ~(1 << 15);
4603 case CONVERT_CK_RGB24
:
4605 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4607 for (y
= 0; y
< height
; y
++)
4609 source
= src
+ pitch
* y
;
4610 dest
= dst
+ outpitch
* y
;
4611 for (x
= 0; x
< width
; x
++) {
4612 DWORD color
= ((DWORD
)source
[0] << 16) + ((DWORD
)source
[1] << 8) + (DWORD
)source
[2] ;
4613 DWORD dstcolor
= color
<< 8;
4614 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4615 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4617 *(DWORD
*)dest
= dstcolor
;
4625 case CONVERT_RGB32_888
:
4627 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4629 for (y
= 0; y
< height
; y
++)
4631 source
= src
+ pitch
* y
;
4632 dest
= dst
+ outpitch
* y
;
4633 for (x
= 0; x
< width
; x
++) {
4634 DWORD color
= 0xffffff & *(const DWORD
*)source
;
4635 DWORD dstcolor
= color
<< 8;
4636 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4637 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4639 *(DWORD
*)dest
= dstcolor
;
4648 ERR("Unsupported conversion type %#x.\n", convert
);
4653 BOOL
palette9_changed(struct wined3d_surface
*surface
)
4655 struct wined3d_device
*device
= surface
->resource
.device
;
4657 if (surface
->palette
|| (surface
->resource
.format
->id
!= WINED3DFMT_P8_UINT
4658 && surface
->resource
.format
->id
!= WINED3DFMT_P8_UINT_A8_UNORM
))
4660 /* If a ddraw-style palette is attached assume no d3d9 palette change.
4661 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
4666 if (surface
->palette9
)
4668 if (!memcmp(surface
->palette9
, device
->palettes
[device
->currentPalette
], sizeof(PALETTEENTRY
) * 256))
4675 surface
->palette9
= HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
4677 memcpy(surface
->palette9
, device
->palettes
[device
->currentPalette
], sizeof(PALETTEENTRY
) * 256);
4682 void flip_surface(struct wined3d_surface
*front
, struct wined3d_surface
*back
)
4684 /* Flip the surface contents */
4689 front
->hDC
= back
->hDC
;
4693 /* Flip the DIBsection */
4696 BOOL hasDib
= front
->flags
& SFLAG_DIBSECTION
;
4697 tmp
= front
->dib
.DIBsection
;
4698 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
4699 back
->dib
.DIBsection
= tmp
;
4701 if (back
->flags
& SFLAG_DIBSECTION
) front
->flags
|= SFLAG_DIBSECTION
;
4702 else front
->flags
&= ~SFLAG_DIBSECTION
;
4703 if (hasDib
) back
->flags
|= SFLAG_DIBSECTION
;
4704 else back
->flags
&= ~SFLAG_DIBSECTION
;
4707 /* Flip the surface data */
4711 tmp
= front
->dib
.bitmap_data
;
4712 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
4713 back
->dib
.bitmap_data
= tmp
;
4715 tmp
= front
->resource
.allocatedMemory
;
4716 front
->resource
.allocatedMemory
= back
->resource
.allocatedMemory
;
4717 back
->resource
.allocatedMemory
= tmp
;
4719 tmp
= front
->resource
.heapMemory
;
4720 front
->resource
.heapMemory
= back
->resource
.heapMemory
;
4721 back
->resource
.heapMemory
= tmp
;
4726 GLuint tmp_pbo
= front
->pbo
;
4727 front
->pbo
= back
->pbo
;
4728 back
->pbo
= tmp_pbo
;
4731 /* client_memory should not be different, but just in case */
4734 tmp
= front
->dib
.client_memory
;
4735 front
->dib
.client_memory
= back
->dib
.client_memory
;
4736 back
->dib
.client_memory
= tmp
;
4739 /* Flip the opengl texture */
4743 tmp
= back
->texture_name
;
4744 back
->texture_name
= front
->texture_name
;
4745 front
->texture_name
= tmp
;
4747 tmp
= back
->texture_name_srgb
;
4748 back
->texture_name_srgb
= front
->texture_name_srgb
;
4749 front
->texture_name_srgb
= tmp
;
4751 resource_unload(&back
->resource
);
4752 resource_unload(&front
->resource
);
4756 DWORD tmp_flags
= back
->flags
;
4757 back
->flags
= front
->flags
;
4758 front
->flags
= tmp_flags
;
4762 /* Does a direct frame buffer -> texture copy. Stretching is done with single
4763 * pixel copy calls. */
4764 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
4765 const RECT
*src_rect
, const RECT
*dst_rect_in
, WINED3DTEXTUREFILTERTYPE Filter
)
4767 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4770 struct wined3d_context
*context
;
4771 BOOL upsidedown
= FALSE
;
4772 RECT dst_rect
= *dst_rect_in
;
4774 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4775 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4777 if(dst_rect
.top
> dst_rect
.bottom
) {
4778 UINT tmp
= dst_rect
.bottom
;
4779 dst_rect
.bottom
= dst_rect
.top
;
4784 context
= context_acquire(device
, src_surface
);
4785 context_apply_blit_state(context
, device
);
4786 surface_internal_preload(dst_surface
, SRGB_RGB
);
4789 /* Bind the target texture */
4790 glBindTexture(dst_surface
->texture_target
, dst_surface
->texture_name
);
4791 checkGLcall("glBindTexture");
4792 if (surface_is_offscreen(src_surface
))
4794 TRACE("Reading from an offscreen target\n");
4795 upsidedown
= !upsidedown
;
4796 glReadBuffer(device
->offscreenBuffer
);
4800 glReadBuffer(surface_get_gl_buffer(src_surface
));
4802 checkGLcall("glReadBuffer");
4804 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
4805 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
4807 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4809 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4811 if(Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
) {
4812 ERR("Texture filtering not supported in direct blit\n");
4815 else if ((Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
)
4816 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
4818 ERR("Texture filtering not supported in direct blit\n");
4822 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4823 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
4825 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
4827 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4828 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
4829 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
4830 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
4834 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
4835 /* I have to process this row by row to swap the image,
4836 * otherwise it would be upside down, so stretching in y direction
4837 * doesn't cost extra time
4839 * However, stretching in x direction can be avoided if not necessary
4841 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
4842 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4844 /* Well, that stuff works, but it's very slow.
4845 * find a better way instead
4849 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
4851 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4852 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
4853 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
4858 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4859 dst_rect
.left
/* x offset */, row
/* y offset */,
4860 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
4864 checkGLcall("glCopyTexSubImage2D");
4867 context_release(context
);
4869 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
4870 * path is never entered
4872 surface_modify_location(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
4875 /* Uses the hardware to stretch and flip the image */
4876 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
4877 const RECT
*src_rect
, const RECT
*dst_rect_in
, WINED3DTEXTUREFILTERTYPE Filter
)
4879 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4880 struct wined3d_swapchain
*src_swapchain
= NULL
;
4881 GLuint src
, backup
= 0;
4882 float left
, right
, top
, bottom
; /* Texture coordinates */
4883 UINT fbwidth
= src_surface
->resource
.width
;
4884 UINT fbheight
= src_surface
->resource
.height
;
4885 struct wined3d_context
*context
;
4886 GLenum drawBuffer
= GL_BACK
;
4887 GLenum texture_target
;
4888 BOOL noBackBufferBackup
;
4890 BOOL upsidedown
= FALSE
;
4891 RECT dst_rect
= *dst_rect_in
;
4893 TRACE("Using hwstretch blit\n");
4894 /* Activate the Proper context for reading from the source surface, set it up for blitting */
4895 context
= context_acquire(device
, src_surface
);
4896 context_apply_blit_state(context
, device
);
4897 surface_internal_preload(dst_surface
, SRGB_RGB
);
4899 src_offscreen
= surface_is_offscreen(src_surface
);
4900 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
4901 if (!noBackBufferBackup
&& !src_surface
->texture_name
)
4903 /* Get it a description */
4904 surface_internal_preload(src_surface
, SRGB_RGB
);
4908 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
4909 * This way we don't have to wait for the 2nd readback to finish to leave this function.
4911 if (context
->aux_buffers
>= 2)
4913 /* Got more than one aux buffer? Use the 2nd aux buffer */
4914 drawBuffer
= GL_AUX1
;
4916 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
4918 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
4919 drawBuffer
= GL_AUX0
;
4922 if(noBackBufferBackup
) {
4923 glGenTextures(1, &backup
);
4924 checkGLcall("glGenTextures");
4925 glBindTexture(GL_TEXTURE_2D
, backup
);
4926 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
4927 texture_target
= GL_TEXTURE_2D
;
4929 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
4930 * we are reading from the back buffer, the backup can be used as source texture
4932 texture_target
= src_surface
->texture_target
;
4933 glBindTexture(texture_target
, src_surface
->texture_name
);
4934 checkGLcall("glBindTexture(texture_target, src_surface->texture_name)");
4935 glEnable(texture_target
);
4936 checkGLcall("glEnable(texture_target)");
4938 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
4939 src_surface
->flags
&= ~SFLAG_INTEXTURE
;
4942 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4943 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4945 if(dst_rect
.top
> dst_rect
.bottom
) {
4946 UINT tmp
= dst_rect
.bottom
;
4947 dst_rect
.bottom
= dst_rect
.top
;
4954 TRACE("Reading from an offscreen target\n");
4955 upsidedown
= !upsidedown
;
4956 glReadBuffer(device
->offscreenBuffer
);
4960 glReadBuffer(surface_get_gl_buffer(src_surface
));
4963 /* TODO: Only back up the part that will be overwritten */
4964 glCopyTexSubImage2D(texture_target
, 0,
4965 0, 0 /* read offsets */,
4970 checkGLcall("glCopyTexSubImage2D");
4972 /* No issue with overriding these - the sampler is dirty due to blit usage */
4973 glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
,
4974 wined3d_gl_mag_filter(magLookup
, Filter
));
4975 checkGLcall("glTexParameteri");
4976 glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
4977 wined3d_gl_min_mip_filter(minMipLookup
, Filter
, WINED3DTEXF_NONE
));
4978 checkGLcall("glTexParameteri");
4980 if (src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
4981 src_swapchain
= src_surface
->container
.u
.swapchain
;
4982 if (!src_swapchain
|| src_surface
== src_swapchain
->back_buffers
[0])
4984 src
= backup
? backup
: src_surface
->texture_name
;
4988 glReadBuffer(GL_FRONT
);
4989 checkGLcall("glReadBuffer(GL_FRONT)");
4991 glGenTextures(1, &src
);
4992 checkGLcall("glGenTextures(1, &src)");
4993 glBindTexture(GL_TEXTURE_2D
, src
);
4994 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
4996 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
4997 * out for power of 2 sizes
4999 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
5000 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
5001 checkGLcall("glTexImage2D");
5002 glCopyTexSubImage2D(GL_TEXTURE_2D
, 0,
5003 0, 0 /* read offsets */,
5008 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5009 checkGLcall("glTexParameteri");
5010 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5011 checkGLcall("glTexParameteri");
5013 glReadBuffer(GL_BACK
);
5014 checkGLcall("glReadBuffer(GL_BACK)");
5016 if(texture_target
!= GL_TEXTURE_2D
) {
5017 glDisable(texture_target
);
5018 glEnable(GL_TEXTURE_2D
);
5019 texture_target
= GL_TEXTURE_2D
;
5022 checkGLcall("glEnd and previous");
5024 left
= src_rect
->left
;
5025 right
= src_rect
->right
;
5029 top
= src_surface
->resource
.height
- src_rect
->top
;
5030 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
5034 top
= src_surface
->resource
.height
- src_rect
->bottom
;
5035 bottom
= src_surface
->resource
.height
- src_rect
->top
;
5038 if (src_surface
->flags
& SFLAG_NORMCOORD
)
5040 left
/= src_surface
->pow2Width
;
5041 right
/= src_surface
->pow2Width
;
5042 top
/= src_surface
->pow2Height
;
5043 bottom
/= src_surface
->pow2Height
;
5046 /* draw the source texture stretched and upside down. The correct surface is bound already */
5047 glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
5048 glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
5050 context_set_draw_buffer(context
, drawBuffer
);
5051 glReadBuffer(drawBuffer
);
5055 glTexCoord2f(left
, bottom
);
5059 glTexCoord2f(left
, top
);
5060 glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
5063 glTexCoord2f(right
, top
);
5064 glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
5067 glTexCoord2f(right
, bottom
);
5068 glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
5070 checkGLcall("glEnd and previous");
5072 if (texture_target
!= dst_surface
->texture_target
)
5074 glDisable(texture_target
);
5075 glEnable(dst_surface
->texture_target
);
5076 texture_target
= dst_surface
->texture_target
;
5079 /* Now read the stretched and upside down image into the destination texture */
5080 glBindTexture(texture_target
, dst_surface
->texture_name
);
5081 checkGLcall("glBindTexture");
5082 glCopyTexSubImage2D(texture_target
,
5084 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
5085 0, 0, /* We blitted the image to the origin */
5086 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
5087 checkGLcall("glCopyTexSubImage2D");
5089 if(drawBuffer
== GL_BACK
) {
5090 /* Write the back buffer backup back */
5092 if(texture_target
!= GL_TEXTURE_2D
) {
5093 glDisable(texture_target
);
5094 glEnable(GL_TEXTURE_2D
);
5095 texture_target
= GL_TEXTURE_2D
;
5097 glBindTexture(GL_TEXTURE_2D
, backup
);
5098 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
5102 if (texture_target
!= src_surface
->texture_target
)
5104 glDisable(texture_target
);
5105 glEnable(src_surface
->texture_target
);
5106 texture_target
= src_surface
->texture_target
;
5108 glBindTexture(src_surface
->texture_target
, src_surface
->texture_name
);
5109 checkGLcall("glBindTexture(src_surface->texture_target, src_surface->texture_name)");
5114 glTexCoord2f(0.0f
, 0.0f
);
5115 glVertex2i(0, fbheight
);
5118 glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
5122 glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
5123 (float)fbheight
/ (float)src_surface
->pow2Height
);
5124 glVertex2i(fbwidth
, 0);
5127 glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
5128 glVertex2i(fbwidth
, fbheight
);
5131 glDisable(texture_target
);
5132 checkGLcall("glDisable(texture_target)");
5135 if (src
!= src_surface
->texture_name
&& src
!= backup
)
5137 glDeleteTextures(1, &src
);
5138 checkGLcall("glDeleteTextures(1, &src)");
5141 glDeleteTextures(1, &backup
);
5142 checkGLcall("glDeleteTextures(1, &backup)");
5147 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5149 context_release(context
);
5151 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5152 * path is never entered
5154 surface_modify_location(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
5157 /* Front buffer coordinates are always full screen coordinates, but our GL
5158 * drawable is limited to the window's client area. The sysmem and texture
5159 * copies do have the full screen size. Note that GL has a bottom-left
5160 * origin, while D3D has a top-left origin. */
5161 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
5163 UINT drawable_height
;
5165 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
5166 && surface
== surface
->container
.u
.swapchain
->front_buffer
)
5168 POINT offset
= {0, 0};
5171 ScreenToClient(window
, &offset
);
5172 OffsetRect(rect
, offset
.x
, offset
.y
);
5174 GetClientRect(window
, &windowsize
);
5175 drawable_height
= windowsize
.bottom
- windowsize
.top
;
5179 drawable_height
= surface
->resource
.height
;
5182 rect
->top
= drawable_height
- rect
->top
;
5183 rect
->bottom
= drawable_height
- rect
->bottom
;
5186 static void surface_blt_to_drawable(struct wined3d_device
*device
,
5187 WINED3DTEXTUREFILTERTYPE filter
, BOOL color_key
,
5188 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
5189 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
5191 struct wined3d_context
*context
;
5192 RECT src_rect
, dst_rect
;
5194 src_rect
= *src_rect_in
;
5195 dst_rect
= *dst_rect_in
;
5197 /* Make sure the surface is up-to-date. This should probably use
5198 * surface_load_location() and worry about the destination surface too,
5199 * unless we're overwriting it completely. */
5200 surface_internal_preload(src_surface
, SRGB_RGB
);
5202 /* Activate the destination context, set it up for blitting */
5203 context
= context_acquire(device
, dst_surface
);
5204 context_apply_blit_state(context
, device
);
5206 if (!surface_is_offscreen(dst_surface
))
5207 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
5209 device
->blitter
->set_shader(device
->blit_priv
, context
->gl_info
, src_surface
);
5215 glEnable(GL_ALPHA_TEST
);
5216 checkGLcall("glEnable(GL_ALPHA_TEST)");
5218 /* When the primary render target uses P8, the alpha component
5219 * contains the palette index. Which means that the colorkey is one of
5220 * the palette entries. In other cases pixels that should be masked
5221 * away have alpha set to 0. */
5222 if (primary_render_target_is_p8(device
))
5223 glAlphaFunc(GL_NOTEQUAL
, (float)src_surface
->SrcBltCKey
.dwColorSpaceLowValue
/ 256.0f
);
5225 glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
5226 checkGLcall("glAlphaFunc");
5230 glDisable(GL_ALPHA_TEST
);
5231 checkGLcall("glDisable(GL_ALPHA_TEST)");
5234 draw_textured_quad(src_surface
, &src_rect
, &dst_rect
, filter
);
5238 glDisable(GL_ALPHA_TEST
);
5239 checkGLcall("glDisable(GL_ALPHA_TEST)");
5244 /* Leave the opengl state valid for blitting */
5245 device
->blitter
->unset_shader(context
->gl_info
);
5247 if (wined3d_settings
.strict_draw_ordering
5248 || (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
5249 && (dst_surface
->container
.u
.swapchain
->front_buffer
== dst_surface
)))
5250 wglFlush(); /* Flush to ensure ordering across contexts. */
5252 context_release(context
);
5255 /* Do not call while under the GL lock. */
5256 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const WINED3DCOLORVALUE
*color
)
5258 struct wined3d_device
*device
= s
->resource
.device
;
5259 const struct blit_shader
*blitter
;
5261 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_FILL
,
5262 NULL
, 0, 0, NULL
, rect
, s
->resource
.usage
, s
->resource
.pool
, s
->resource
.format
);
5265 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5266 return WINED3DERR_INVALIDCALL
;
5269 return blitter
->color_fill(device
, s
, rect
, color
);
5272 /* Do not call while under the GL lock. */
5273 static HRESULT
IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5274 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
,
5275 WINED3DTEXTUREFILTERTYPE Filter
)
5277 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5278 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
5279 struct wined3d_swapchain
*srcSwapchain
= NULL
, *dstSwapchain
= NULL
;
5281 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5282 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5283 flags
, DDBltFx
, debug_d3dtexturefiltertype(Filter
));
5285 /* Get the swapchain. One of the surfaces has to be a primary surface */
5286 if (dst_surface
->resource
.pool
== WINED3DPOOL_SYSTEMMEM
)
5288 WARN("Destination is in sysmem, rejecting gl blt\n");
5289 return WINED3DERR_INVALIDCALL
;
5292 if (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
5293 dstSwapchain
= dst_surface
->container
.u
.swapchain
;
5297 if (src_surface
->resource
.pool
== WINED3DPOOL_SYSTEMMEM
)
5299 WARN("Src is in sysmem, rejecting gl blt\n");
5300 return WINED3DERR_INVALIDCALL
;
5303 if (src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
5304 srcSwapchain
= src_surface
->container
.u
.swapchain
;
5307 /* Early sort out of cases where no render target is used */
5308 if (!dstSwapchain
&& !srcSwapchain
5309 && src_surface
!= device
->fb
.render_targets
[0]
5310 && dst_surface
!= device
->fb
.render_targets
[0])
5312 TRACE("No surface is render target, not using hardware blit.\n");
5313 return WINED3DERR_INVALIDCALL
;
5316 /* No destination color keying supported */
5317 if (flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
))
5319 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5320 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5321 return WINED3DERR_INVALIDCALL
;
5324 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
5325 if (dstSwapchain
&& dstSwapchain
== srcSwapchain
&& dstSwapchain
->back_buffers
5326 && dst_surface
== dstSwapchain
->front_buffer
5327 && src_surface
== dstSwapchain
->back_buffers
[0])
5329 /* Half-Life does a Blt from the back buffer to the front buffer,
5330 * Full surface size, no flags... Use present instead
5332 * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
5335 /* Check rects - wined3d_swapchain_present() doesn't handle them. */
5338 TRACE("Looking if a Present can be done...\n");
5339 /* Source Rectangle must be full surface */
5340 if (src_rect
->left
|| src_rect
->top
5341 || src_rect
->right
!= src_surface
->resource
.width
5342 || src_rect
->bottom
!= src_surface
->resource
.height
)
5344 TRACE("No, Source rectangle doesn't match\n");
5348 /* No stretching may occur */
5349 if (src_rect
->right
!= dst_rect
->right
- dst_rect
->left
5350 || src_rect
->bottom
!= dst_rect
->bottom
- dst_rect
->top
)
5352 TRACE("No, stretching is done\n");
5356 /* Destination must be full surface or match the clipping rectangle */
5357 if (dst_surface
->clipper
&& dst_surface
->clipper
->hWnd
)
5361 GetClientRect(dst_surface
->clipper
->hWnd
, &cliprect
);
5362 pos
[0].x
= dst_rect
->left
;
5363 pos
[0].y
= dst_rect
->top
;
5364 pos
[1].x
= dst_rect
->right
;
5365 pos
[1].y
= dst_rect
->bottom
;
5366 MapWindowPoints(GetDesktopWindow(), dst_surface
->clipper
->hWnd
, pos
, 2);
5368 if (pos
[0].x
!= cliprect
.left
|| pos
[0].y
!= cliprect
.top
5369 || pos
[1].x
!= cliprect
.right
|| pos
[1].y
!= cliprect
.bottom
)
5371 TRACE("No, dest rectangle doesn't match(clipper)\n");
5372 TRACE("Clip rect at %s\n", wine_dbgstr_rect(&cliprect
));
5373 TRACE("Blt dest: %s\n", wine_dbgstr_rect(dst_rect
));
5377 else if (dst_rect
->left
|| dst_rect
->top
5378 || dst_rect
->right
!= dst_surface
->resource
.width
5379 || dst_rect
->bottom
!= dst_surface
->resource
.height
)
5381 TRACE("No, dest rectangle doesn't match(surface size)\n");
5387 /* These flags are unimportant for the flag check, remove them */
5388 if (!(flags
& ~(WINEDDBLT_DONOTWAIT
| WINEDDBLT_WAIT
)))
5390 WINED3DSWAPEFFECT orig_swap
= dstSwapchain
->presentParms
.SwapEffect
;
5392 /* The idea behind this is that a glReadPixels and a glDrawPixels call
5393 * take very long, while a flip is fast.
5394 * This applies to Half-Life, which does such Blts every time it finished
5395 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
5396 * menu. This is also used by all apps when they do windowed rendering
5398 * The problem is that flipping is not really the same as copying. After a
5399 * Blt the front buffer is a copy of the back buffer, and the back buffer is
5400 * untouched. Therefore it's necessary to override the swap effect
5401 * and to set it back after the flip.
5403 * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
5407 dstSwapchain
->presentParms
.SwapEffect
= WINED3DSWAPEFFECT_COPY
;
5408 dstSwapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_IMMEDIATE
;
5410 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead.\n");
5411 wined3d_swapchain_present(dstSwapchain
, NULL
, NULL
, dstSwapchain
->win_handle
, NULL
, 0);
5413 dstSwapchain
->presentParms
.SwapEffect
= orig_swap
;
5420 TRACE("Unsupported blit between buffers on the same swapchain\n");
5421 return WINED3DERR_INVALIDCALL
;
5422 } else if(dstSwapchain
&& dstSwapchain
== srcSwapchain
) {
5423 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5424 return WINED3DERR_INVALIDCALL
;
5425 } else if(dstSwapchain
&& srcSwapchain
) {
5426 FIXME("Implement hardware blit between two different swapchains\n");
5427 return WINED3DERR_INVALIDCALL
;
5429 else if (dstSwapchain
)
5431 /* Handled with regular texture -> swapchain blit */
5432 if (src_surface
== device
->fb
.render_targets
[0])
5433 TRACE("Blit from active render target to a swapchain\n");
5435 else if (srcSwapchain
&& dst_surface
== device
->fb
.render_targets
[0])
5437 FIXME("Implement blit from a swapchain to the active render target\n");
5438 return WINED3DERR_INVALIDCALL
;
5441 if ((srcSwapchain
|| src_surface
== device
->fb
.render_targets
[0]) && !dstSwapchain
)
5443 /* Blit from render target to texture */
5446 /* P8 read back is not implemented */
5447 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
5448 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
5450 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5451 return WINED3DERR_INVALIDCALL
;
5454 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
5456 TRACE("Color keying not supported by frame buffer to texture blit\n");
5457 return WINED3DERR_INVALIDCALL
;
5458 /* Destination color key is checked above */
5461 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
5466 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5467 * flip the image nor scale it.
5469 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5470 * -> If the app wants a image width an unscaled width, copy it line per line
5471 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5472 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5473 * back buffer. This is slower than reading line per line, thus not used for flipping
5474 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5475 * pixel by pixel. */
5476 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
5477 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
5479 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
5480 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, Filter
);
5482 TRACE("Using hardware stretching to flip / stretch the texture\n");
5483 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, Filter
);
5486 if (!(dst_surface
->flags
& SFLAG_DONOTFREE
))
5488 HeapFree(GetProcessHeap(), 0, dst_surface
->resource
.heapMemory
);
5489 dst_surface
->resource
.allocatedMemory
= NULL
;
5490 dst_surface
->resource
.heapMemory
= NULL
;
5494 dst_surface
->flags
&= ~SFLAG_INSYSMEM
;
5499 else if (src_surface
)
5501 /* Blit from offscreen surface to render target */
5502 DWORD oldCKeyFlags
= src_surface
->CKeyFlags
;
5503 WINEDDCOLORKEY oldBltCKey
= src_surface
->SrcBltCKey
;
5505 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
5507 if (!(flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
5508 && arbfp_blit
.blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5509 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
,
5510 src_surface
->resource
.format
,
5511 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
,
5512 dst_surface
->resource
.format
))
5513 return arbfp_blit_surface(device
, Filter
, src_surface
, src_rect
, dst_surface
, dst_rect
);
5515 if (!device
->blitter
->blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5516 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5517 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5519 FIXME("Unsupported blit operation falling back to software\n");
5520 return WINED3DERR_INVALIDCALL
;
5523 /* Color keying: Check if we have to do a color keyed blt,
5524 * and if not check if a color key is activated.
5526 * Just modify the color keying parameters in the surface and restore them afterwards
5527 * The surface keeps track of the color key last used to load the opengl surface.
5528 * PreLoad will catch the change to the flags and color key and reload if necessary.
5530 if (flags
& WINEDDBLT_KEYSRC
)
5532 /* Use color key from surface */
5534 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
5536 /* Use color key from DDBltFx */
5537 src_surface
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
5538 src_surface
->SrcBltCKey
= DDBltFx
->ddckSrcColorkey
;
5542 /* Do not use color key */
5543 src_surface
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
5546 surface_blt_to_drawable(device
, Filter
, flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
),
5547 src_surface
, src_rect
, dst_surface
, dst_rect
);
5549 /* Restore the color key parameters */
5550 src_surface
->CKeyFlags
= oldCKeyFlags
;
5551 src_surface
->SrcBltCKey
= oldBltCKey
;
5553 surface_modify_location(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
5558 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5559 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5560 return WINED3DERR_INVALIDCALL
;
5563 /* GL locking is done by the caller */
5564 static void surface_depth_blt(const struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
5565 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
5567 struct wined3d_device
*device
= surface
->resource
.device
;
5568 GLint compare_mode
= GL_NONE
;
5569 struct blt_info info
;
5570 GLint old_binding
= 0;
5573 glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
5575 glDisable(GL_CULL_FACE
);
5576 glDisable(GL_BLEND
);
5577 glDisable(GL_ALPHA_TEST
);
5578 glDisable(GL_SCISSOR_TEST
);
5579 glDisable(GL_STENCIL_TEST
);
5580 glEnable(GL_DEPTH_TEST
);
5581 glDepthFunc(GL_ALWAYS
);
5582 glDepthMask(GL_TRUE
);
5583 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
5584 glViewport(x
, y
, w
, h
);
5586 SetRect(&rect
, 0, h
, w
, 0);
5587 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
5588 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5589 glGetIntegerv(info
.binding
, &old_binding
);
5590 glBindTexture(info
.bind_target
, texture
);
5591 if (gl_info
->supported
[ARB_SHADOW
])
5593 glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
5594 if (compare_mode
!= GL_NONE
) glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
5597 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
5598 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
5600 glBegin(GL_TRIANGLE_STRIP
);
5601 glTexCoord3fv(info
.coords
[0]);
5602 glVertex2f(-1.0f
, -1.0f
);
5603 glTexCoord3fv(info
.coords
[1]);
5604 glVertex2f(1.0f
, -1.0f
);
5605 glTexCoord3fv(info
.coords
[2]);
5606 glVertex2f(-1.0f
, 1.0f
);
5607 glTexCoord3fv(info
.coords
[3]);
5608 glVertex2f(1.0f
, 1.0f
);
5611 if (compare_mode
!= GL_NONE
) glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
5612 glBindTexture(info
.bind_target
, old_binding
);
5616 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
5619 void surface_modify_ds_location(struct wined3d_surface
*surface
,
5620 DWORD location
, UINT w
, UINT h
)
5622 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
5624 if (location
& ~SFLAG_DS_LOCATIONS
)
5625 FIXME("Invalid location (%#x) specified.\n", location
);
5627 surface
->ds_current_size
.cx
= w
;
5628 surface
->ds_current_size
.cy
= h
;
5629 surface
->flags
&= ~SFLAG_DS_LOCATIONS
;
5630 surface
->flags
|= location
;
5633 /* Context activation is done by the caller. */
5634 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
5636 struct wined3d_device
*device
= surface
->resource
.device
;
5637 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
5640 TRACE("surface %p, new location %#x.\n", surface
, location
);
5642 /* TODO: Make this work for modes other than FBO */
5643 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
5645 if (!(surface
->flags
& location
))
5647 w
= surface
->ds_current_size
.cx
;
5648 h
= surface
->ds_current_size
.cy
;
5649 surface
->ds_current_size
.cx
= 0;
5650 surface
->ds_current_size
.cy
= 0;
5654 w
= surface
->resource
.width
;
5655 h
= surface
->resource
.height
;
5658 if (surface
->ds_current_size
.cx
== surface
->resource
.width
5659 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
5661 TRACE("Location (%#x) is already up to date.\n", location
);
5665 if (surface
->current_renderbuffer
)
5667 FIXME("Not supported with fixed up depth stencil.\n");
5671 if (!(surface
->flags
& SFLAG_DS_LOCATIONS
))
5673 /* This mostly happens when a depth / stencil is used without being
5674 * cleared first. In principle we could upload from sysmem, or
5675 * explicitly clear before first usage. For the moment there don't
5676 * appear to be a lot of applications depending on this, so a FIXME
5678 FIXME("No up to date depth stencil location.\n");
5679 surface
->flags
|= location
;
5680 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5681 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5685 if (location
== SFLAG_DS_OFFSCREEN
)
5687 GLint old_binding
= 0;
5690 /* The render target is allowed to be smaller than the depth/stencil
5691 * buffer, so the onscreen depth/stencil buffer is potentially smaller
5692 * than the offscreen surface. Don't overwrite the offscreen surface
5693 * with undefined data. */
5694 w
= min(w
, context
->swapchain
->presentParms
.BackBufferWidth
);
5695 h
= min(h
, context
->swapchain
->presentParms
.BackBufferHeight
);
5697 TRACE("Copying onscreen depth buffer to depth texture.\n");
5701 if (!device
->depth_blt_texture
)
5703 glGenTextures(1, &device
->depth_blt_texture
);
5706 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5707 * directly on the FBO texture. That's because we need to flip. */
5708 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5709 context
->swapchain
->front_buffer
, NULL
, SFLAG_INDRAWABLE
);
5710 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
5712 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
5713 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
5717 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
5718 bind_target
= GL_TEXTURE_2D
;
5720 glBindTexture(bind_target
, device
->depth_blt_texture
);
5721 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
5722 * internal format, because the internal format might include stencil
5723 * data. In principle we should copy stencil data as well, but unless
5724 * the driver supports stencil export it's hard to do, and doesn't
5725 * seem to be needed in practice. If the hardware doesn't support
5726 * writing stencil data, the glCopyTexImage2D() call might trigger
5727 * software fallbacks. */
5728 glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
5729 glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5730 glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5731 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
5732 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
5733 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
5734 glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
5735 glBindTexture(bind_target
, old_binding
);
5737 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5738 NULL
, surface
, SFLAG_INTEXTURE
);
5739 context_set_draw_buffer(context
, GL_NONE
);
5740 glReadBuffer(GL_NONE
);
5742 /* Do the actual blit */
5743 surface_depth_blt(surface
, gl_info
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
5744 checkGLcall("depth_blt");
5746 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
5750 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5752 else if (location
== SFLAG_DS_ONSCREEN
)
5754 TRACE("Copying depth texture to onscreen depth buffer.\n");
5758 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5759 context
->swapchain
->front_buffer
, NULL
, SFLAG_INDRAWABLE
);
5760 surface_depth_blt(surface
, gl_info
, surface
->texture_name
,
5761 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
5762 checkGLcall("depth_blt");
5764 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
5768 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5772 ERR("Invalid location (%#x) specified.\n", location
);
5775 surface
->flags
|= location
;
5776 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5777 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5780 void surface_modify_location(struct wined3d_surface
*surface
, DWORD location
, BOOL persistent
)
5782 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
5783 struct wined3d_surface
*overlay
;
5785 TRACE("surface %p, location %s, persistent %#x.\n",
5786 surface
, debug_surflocation(location
), persistent
);
5788 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
5790 if (surface_is_offscreen(surface
))
5792 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same
5793 * for offscreen targets. */
5794 if (location
& (SFLAG_INTEXTURE
| SFLAG_INDRAWABLE
))
5795 location
|= (SFLAG_INTEXTURE
| SFLAG_INDRAWABLE
);
5799 TRACE("Surface %p is an onscreen surface.\n", surface
);
5803 if (location
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)
5804 && gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
5805 location
|= (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
);
5809 if (((surface
->flags
& SFLAG_INTEXTURE
) && !(location
& SFLAG_INTEXTURE
))
5810 || ((surface
->flags
& SFLAG_INSRGBTEX
) && !(location
& SFLAG_INSRGBTEX
)))
5812 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
5814 TRACE("Passing to container.\n");
5815 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
5818 surface
->flags
&= ~SFLAG_LOCATIONS
;
5819 surface
->flags
|= location
;
5821 /* Redraw emulated overlays, if any */
5822 if (location
& SFLAG_INDRAWABLE
&& !list_empty(&surface
->overlays
))
5824 LIST_FOR_EACH_ENTRY(overlay
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
5826 overlay
->surface_ops
->surface_draw_overlay(overlay
);
5832 if ((surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)) && (location
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)))
5834 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
5836 TRACE("Passing to container\n");
5837 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
5840 surface
->flags
&= ~location
;
5843 if (!(surface
->flags
& SFLAG_LOCATIONS
))
5845 ERR("Surface %p does not have any up to date location.\n", surface
);
5849 static DWORD
resource_access_from_location(DWORD location
)
5853 case SFLAG_INSYSMEM
:
5854 return WINED3D_RESOURCE_ACCESS_CPU
;
5856 case SFLAG_INDRAWABLE
:
5857 case SFLAG_INSRGBTEX
:
5858 case SFLAG_INTEXTURE
:
5859 return WINED3D_RESOURCE_ACCESS_GPU
;
5862 FIXME("Unhandled location %#x.\n", location
);
5867 static void surface_load_sysmem(struct wined3d_surface
*surface
,
5868 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
)
5870 surface_prepare_system_memory(surface
);
5872 /* Download the surface to system memory. */
5873 if (surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
))
5875 struct wined3d_device
*device
= surface
->resource
.device
;
5876 struct wined3d_context
*context
= NULL
;
5878 if (!device
->isInDraw
)
5879 context
= context_acquire(device
, NULL
);
5881 surface_bind_and_dirtify(surface
, gl_info
, !(surface
->flags
& SFLAG_INTEXTURE
));
5882 surface_download_data(surface
, gl_info
);
5885 context_release(context
);
5890 /* Note: It might be faster to download into a texture first. */
5891 read_from_framebuffer(surface
, rect
, surface
->resource
.allocatedMemory
,
5892 wined3d_surface_get_pitch(surface
));
5895 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
5896 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
)
5898 struct wined3d_device
*device
= surface
->resource
.device
;
5899 struct wined3d_format format
;
5900 CONVERT_TYPES convert
;
5904 if (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
)
5905 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
5907 if (surface
->flags
& SFLAG_INTEXTURE
)
5911 surface_get_rect(surface
, rect
, &r
);
5912 surface_blt_to_drawable(device
, WINED3DTEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
5917 if ((surface
->flags
& SFLAG_LOCATIONS
) == SFLAG_INSRGBTEX
)
5919 /* This needs colorspace conversion from sRGB to RGB. We take the slow
5920 * path through sysmem. */
5921 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5924 d3dfmt_get_conv(surface
, FALSE
, FALSE
, &format
, &convert
);
5926 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
5927 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
5929 if ((convert
!= NO_CONVERSION
) && (surface
->flags
& SFLAG_PBO
))
5931 struct wined3d_context
*context
= NULL
;
5933 TRACE("Removing the pbo attached to surface %p.\n", surface
);
5935 if (!device
->isInDraw
)
5936 context
= context_acquire(device
, NULL
);
5938 surface_remove_pbo(surface
, gl_info
);
5941 context_release(context
);
5944 if ((convert
!= NO_CONVERSION
) && surface
->resource
.allocatedMemory
)
5946 UINT height
= surface
->resource
.height
;
5947 UINT width
= surface
->resource
.width
;
5948 UINT src_pitch
, dst_pitch
;
5950 byte_count
= format
.conv_byte_count
;
5951 src_pitch
= wined3d_surface_get_pitch(surface
);
5953 /* Stick to the alignment for the converted surface too, makes it
5954 * easier to load the surface. */
5955 dst_pitch
= width
* byte_count
;
5956 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
5958 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
5960 ERR("Out of memory (%u).\n", dst_pitch
* height
);
5961 return E_OUTOFMEMORY
;
5964 d3dfmt_convert_surface(surface
->resource
.allocatedMemory
, mem
,
5965 src_pitch
, width
, height
, dst_pitch
, convert
, surface
);
5967 surface
->flags
|= SFLAG_CONVERTED
;
5971 surface
->flags
&= ~SFLAG_CONVERTED
;
5972 mem
= surface
->resource
.allocatedMemory
;
5973 byte_count
= format
.byte_count
;
5976 flush_to_framebuffer_drawpixels(surface
, rect
, format
.glFormat
, format
.glType
, byte_count
, mem
);
5978 /* Don't delete PBO memory. */
5979 if ((mem
!= surface
->resource
.allocatedMemory
) && !(surface
->flags
& SFLAG_PBO
))
5980 HeapFree(GetProcessHeap(), 0, mem
);
5985 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
5986 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
, BOOL srgb
)
5988 const DWORD attach_flags
= WINED3DFMT_FLAG_FBO_ATTACHABLE
| WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
;
5989 RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
5990 struct wined3d_device
*device
= surface
->resource
.device
;
5991 struct wined3d_context
*context
= NULL
;
5992 UINT width
, src_pitch
, dst_pitch
;
5993 struct wined3d_bo_address data
;
5994 struct wined3d_format format
;
5995 POINT dst_point
= {0, 0};
5996 CONVERT_TYPES convert
;
5999 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
6000 && surface_is_offscreen(surface
)
6001 && (surface
->flags
& SFLAG_INDRAWABLE
))
6003 read_from_framebuffer_texture(surface
, srgb
);
6008 if (surface
->flags
& (SFLAG_INSRGBTEX
| SFLAG_INTEXTURE
)
6009 && (surface
->resource
.format
->flags
& attach_flags
) == attach_flags
6010 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
6011 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
6012 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
6015 surface_blt_fbo(device
, WINED3DTEXF_POINT
, surface
, SFLAG_INTEXTURE
,
6016 &src_rect
, surface
, SFLAG_INSRGBTEX
, &src_rect
);
6018 surface_blt_fbo(device
, WINED3DTEXF_POINT
, surface
, SFLAG_INSRGBTEX
,
6019 &src_rect
, surface
, SFLAG_INTEXTURE
, &src_rect
);
6024 /* Upload from system memory */
6026 d3dfmt_get_conv(surface
, TRUE
/* We need color keying */,
6027 TRUE
/* We will use textures */, &format
, &convert
);
6031 if ((surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSYSMEM
)) == SFLAG_INTEXTURE
)
6033 /* Performance warning... */
6034 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
6035 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
6040 if ((surface
->flags
& (SFLAG_INSRGBTEX
| SFLAG_INSYSMEM
)) == SFLAG_INSRGBTEX
)
6042 /* Performance warning... */
6043 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
6044 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
6048 if (!(surface
->flags
& SFLAG_INSYSMEM
))
6050 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6051 /* Lets hope we get it from somewhere... */
6052 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
6055 if (!device
->isInDraw
)
6056 context
= context_acquire(device
, NULL
);
6058 surface_prepare_texture(surface
, gl_info
, srgb
);
6059 surface_bind_and_dirtify(surface
, gl_info
, srgb
);
6061 if (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
)
6063 surface
->flags
|= SFLAG_GLCKEY
;
6064 surface
->glCKey
= surface
->SrcBltCKey
;
6066 else surface
->flags
&= ~SFLAG_GLCKEY
;
6068 width
= surface
->resource
.width
;
6069 src_pitch
= wined3d_surface_get_pitch(surface
);
6071 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6072 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6074 if ((convert
!= NO_CONVERSION
|| format
.convert
) && (surface
->flags
& SFLAG_PBO
))
6076 TRACE("Removing the pbo attached to surface %p.\n", surface
);
6077 surface_remove_pbo(surface
, gl_info
);
6082 /* This code is entered for texture formats which need a fixup. */
6083 UINT height
= surface
->resource
.height
;
6085 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6086 dst_pitch
= width
* format
.conv_byte_count
;
6087 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
6089 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
6091 ERR("Out of memory (%u).\n", dst_pitch
* height
);
6093 context_release(context
);
6094 return E_OUTOFMEMORY
;
6096 format
.convert(surface
->resource
.allocatedMemory
, mem
, src_pitch
, width
, height
);
6098 else if (convert
!= NO_CONVERSION
&& surface
->resource
.allocatedMemory
)
6100 /* This code is only entered for color keying fixups */
6101 UINT height
= surface
->resource
.height
;
6103 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6104 dst_pitch
= width
* format
.conv_byte_count
;
6105 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
6107 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
6109 ERR("Out of memory (%u).\n", dst_pitch
* height
);
6111 context_release(context
);
6112 return E_OUTOFMEMORY
;
6114 d3dfmt_convert_surface(surface
->resource
.allocatedMemory
, mem
, src_pitch
,
6115 width
, height
, dst_pitch
, convert
, surface
);
6119 mem
= surface
->resource
.allocatedMemory
;
6122 data
.buffer_object
= surface
->flags
& SFLAG_PBO
? surface
->pbo
: 0;
6124 surface_upload_data(surface
, gl_info
, &format
, &src_rect
, width
, &dst_point
, srgb
, &data
);
6127 context_release(context
);
6129 /* Don't delete PBO memory. */
6130 if ((mem
!= surface
->resource
.allocatedMemory
) && !(surface
->flags
& SFLAG_PBO
))
6131 HeapFree(GetProcessHeap(), 0, mem
);
6136 HRESULT
surface_load_location(struct wined3d_surface
*surface
, DWORD location
, const RECT
*rect
)
6138 struct wined3d_device
*device
= surface
->resource
.device
;
6139 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6140 BOOL in_fbo
= FALSE
;
6143 TRACE("surface %p, location %s, rect %s.\n", surface
, debug_surflocation(location
), wine_dbgstr_rect(rect
));
6145 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
6147 if (location
== SFLAG_INTEXTURE
)
6149 struct wined3d_context
*context
= context_acquire(device
, NULL
);
6150 surface_load_ds_location(surface
, context
, SFLAG_DS_OFFSCREEN
);
6151 context_release(context
);
6156 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location
));
6157 return WINED3DERR_INVALIDCALL
;
6161 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6163 if (surface_is_offscreen(surface
))
6165 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same
6166 * for offscreen targets. Prefer SFLAG_INTEXTURE. */
6167 if (location
== SFLAG_INDRAWABLE
)
6168 location
= SFLAG_INTEXTURE
;
6173 TRACE("Surface %p is an onscreen surface.\n", surface
);
6177 if (location
== SFLAG_INSRGBTEX
&& gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
6178 location
= SFLAG_INTEXTURE
;
6180 if (surface
->flags
& location
)
6182 TRACE("Location already up to date.\n");
6186 if (WARN_ON(d3d_surface
))
6188 DWORD required_access
= resource_access_from_location(location
);
6189 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
6190 WARN("Operation requires %#x access, but surface only has %#x.\n",
6191 required_access
, surface
->resource
.access_flags
);
6194 if (!(surface
->flags
& SFLAG_LOCATIONS
))
6196 ERR("Surface %p does not have any up to date location.\n", surface
);
6197 surface
->flags
|= SFLAG_LOST
;
6198 return WINED3DERR_DEVICELOST
;
6203 case SFLAG_INSYSMEM
:
6204 surface_load_sysmem(surface
, gl_info
, rect
);
6207 case SFLAG_INDRAWABLE
:
6208 if (FAILED(hr
= surface_load_drawable(surface
, gl_info
, rect
)))
6212 case SFLAG_INTEXTURE
:
6213 case SFLAG_INSRGBTEX
:
6214 if (FAILED(hr
= surface_load_texture(surface
, gl_info
, rect
, location
== SFLAG_INSRGBTEX
)))
6219 ERR("Don't know how to handle location %#x.\n", location
);
6225 surface
->flags
|= location
;
6227 if (location
!= SFLAG_INSYSMEM
&& (surface
->flags
& SFLAG_INSYSMEM
))
6228 surface_evict_sysmem(surface
);
6231 if (in_fbo
&& (surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INDRAWABLE
)))
6233 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
6234 surface
->flags
|= (SFLAG_INTEXTURE
| SFLAG_INDRAWABLE
);
6237 if (surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)
6238 && gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
6240 surface
->flags
|= (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
);
6246 BOOL
surface_is_offscreen(const struct wined3d_surface
*surface
)
6248 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
6250 /* Not on a swapchain - must be offscreen */
6251 if (surface
->container
.type
!= WINED3D_CONTAINER_SWAPCHAIN
) return TRUE
;
6253 /* The front buffer is always onscreen */
6254 if (surface
== swapchain
->front_buffer
) return FALSE
;
6256 /* If the swapchain is rendered to an FBO, the backbuffer is
6257 * offscreen, otherwise onscreen */
6258 return swapchain
->render_to_fbo
;
6261 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
6262 /* Context activation is done by the caller. */
6263 static void ffp_blit_free(struct wined3d_device
*device
) { }
6265 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6266 /* Context activation is done by the caller. */
6267 static void ffp_blit_p8_upload_palette(const struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
6270 BOOL colorkey_active
= (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
) ? TRUE
: FALSE
;
6272 d3dfmt_p8_init_palette(surface
, table
, colorkey_active
);
6274 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6276 GL_EXTCALL(glColorTableEXT(surface
->texture_target
, GL_RGBA
, 256, GL_RGBA
, GL_UNSIGNED_BYTE
, table
));
6280 /* Context activation is done by the caller. */
6281 static HRESULT
ffp_blit_set(void *blit_priv
, const struct wined3d_gl_info
*gl_info
, struct wined3d_surface
*surface
)
6283 enum complex_fixup fixup
= get_complex_fixup(surface
->resource
.format
->color_fixup
);
6285 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6286 * else the surface is converted in software at upload time in LoadLocation.
6288 if(fixup
== COMPLEX_FIXUP_P8
&& gl_info
->supported
[EXT_PALETTED_TEXTURE
])
6289 ffp_blit_p8_upload_palette(surface
, gl_info
);
6292 glEnable(surface
->texture_target
);
6293 checkGLcall("glEnable(surface->texture_target)");
6298 /* Context activation is done by the caller. */
6299 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
6302 glDisable(GL_TEXTURE_2D
);
6303 checkGLcall("glDisable(GL_TEXTURE_2D)");
6304 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
6306 glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
6307 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6309 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
6311 glDisable(GL_TEXTURE_RECTANGLE_ARB
);
6312 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6317 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
6318 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
6319 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
6321 enum complex_fixup src_fixup
;
6325 case WINED3D_BLIT_OP_COLOR_BLIT
:
6326 src_fixup
= get_complex_fixup(src_format
->color_fixup
);
6327 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
6329 TRACE("Checking support for fixup:\n");
6330 dump_color_fixup_desc(src_format
->color_fixup
);
6333 if (!is_identity_fixup(dst_format
->color_fixup
))
6335 TRACE("Destination fixups are not supported\n");
6339 if (src_fixup
== COMPLEX_FIXUP_P8
&& gl_info
->supported
[EXT_PALETTED_TEXTURE
])
6341 TRACE("P8 fixup supported\n");
6345 /* We only support identity conversions. */
6346 if (is_identity_fixup(src_format
->color_fixup
))
6352 TRACE("[FAILED]\n");
6355 case WINED3D_BLIT_OP_COLOR_FILL
:
6356 if (dst_pool
== WINED3DPOOL_SYSTEMMEM
)
6359 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6361 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
6364 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
6366 TRACE("Color fill not supported\n");
6370 /* FIXME: We should reject color fills on formats with fixups,
6371 * but this would break P8 color fills for example. */
6375 case WINED3D_BLIT_OP_DEPTH_FILL
:
6379 TRACE("Unsupported blit_op=%d\n", blit_op
);
6384 /* Do not call while under the GL lock. */
6385 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
6386 const RECT
*dst_rect
, const WINED3DCOLORVALUE
*color
)
6388 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
6389 struct wined3d_fb_state fb
= {&dst_surface
, NULL
};
6391 return device_clear_render_targets(device
, 1, &fb
,
6392 1, dst_rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
6395 /* Do not call while under the GL lock. */
6396 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
,
6397 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
6399 const RECT draw_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
6400 struct wined3d_fb_state fb
= {NULL
, surface
};
6402 return device_clear_render_targets(device
, 0, &fb
,
6403 1, rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
6406 const struct blit_shader ffp_blit
= {
6412 ffp_blit_color_fill
,
6413 ffp_blit_depth_fill
,
6416 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
6421 /* Context activation is done by the caller. */
6422 static void cpu_blit_free(struct wined3d_device
*device
)
6426 /* Context activation is done by the caller. */
6427 static HRESULT
cpu_blit_set(void *blit_priv
, const struct wined3d_gl_info
*gl_info
, struct wined3d_surface
*surface
)
6432 /* Context activation is done by the caller. */
6433 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
6437 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
6438 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
6439 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
6441 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
6449 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
6450 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
6451 const WINEDDBLTFX
*fx
, WINED3DTEXTUREFILTERTYPE filter
)
6453 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
6454 const struct wined3d_format
*src_format
, *dst_format
;
6455 struct wined3d_surface
*orig_src
= src_surface
;
6456 WINED3DLOCKED_RECT dlock
, slock
;
6457 HRESULT hr
= WINED3D_OK
;
6463 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6464 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
6465 flags
, fx
, debug_d3dtexturefiltertype(filter
));
6475 full_rect
.right
= dst_surface
->resource
.width
;
6476 full_rect
.bottom
= dst_surface
->resource
.height
;
6477 IntersectRect(&xdst
, &full_rect
, dst_rect
);
6481 BOOL clip_horiz
, clip_vert
;
6484 clip_horiz
= xdst
.left
< 0 || xdst
.right
> (int)dst_surface
->resource
.width
;
6485 clip_vert
= xdst
.top
< 0 || xdst
.bottom
> (int)dst_surface
->resource
.height
;
6487 if (clip_vert
|| clip_horiz
)
6489 /* Now check if this is a special case or not... */
6490 if ((flags
& WINEDDBLT_DDFX
)
6491 || (clip_horiz
&& xdst
.right
- xdst
.left
!= xsrc
.right
- xsrc
.left
)
6492 || (clip_vert
&& xdst
.bottom
- xdst
.top
!= xsrc
.bottom
- xsrc
.top
))
6494 WARN("Out of screen rectangle in special case. Not handled right now.\n");
6502 xsrc
.left
-= xdst
.left
;
6505 if (xdst
.right
> dst_surface
->resource
.width
)
6507 xsrc
.right
-= (xdst
.right
- (int)dst_surface
->resource
.width
);
6508 xdst
.right
= (int)dst_surface
->resource
.width
;
6516 xsrc
.top
-= xdst
.top
;
6519 if (xdst
.bottom
> dst_surface
->resource
.height
)
6521 xsrc
.bottom
-= (xdst
.bottom
- (int)dst_surface
->resource
.height
);
6522 xdst
.bottom
= (int)dst_surface
->resource
.height
;
6526 /* And check if after clipping something is still to be done... */
6527 if ((xdst
.right
<= 0) || (xdst
.bottom
<= 0)
6528 || (xdst
.left
>= (int)dst_surface
->resource
.width
)
6529 || (xdst
.top
>= (int)dst_surface
->resource
.height
)
6530 || (xsrc
.right
<= 0) || (xsrc
.bottom
<= 0)
6531 || (xsrc
.left
>= (int)src_surface
->resource
.width
)
6532 || (xsrc
.top
>= (int)src_surface
->resource
.height
))
6534 TRACE("Nothing to be done after clipping.\n");
6540 if (src_surface
== dst_surface
)
6542 wined3d_surface_map(dst_surface
, &dlock
, NULL
, 0);
6544 src_format
= dst_surface
->resource
.format
;
6545 dst_format
= src_format
;
6549 dst_format
= dst_surface
->resource
.format
;
6552 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
6554 src_surface
= surface_convert_format(src_surface
, dst_format
->id
);
6557 /* The conv function writes a FIXME */
6558 WARN("Cannot convert source surface format to dest format.\n");
6562 wined3d_surface_map(src_surface
, &slock
, NULL
, WINED3DLOCK_READONLY
);
6563 src_format
= src_surface
->resource
.format
;
6567 src_format
= dst_format
;
6570 wined3d_surface_map(dst_surface
, &dlock
, &xdst
, 0);
6572 wined3d_surface_map(dst_surface
, &dlock
, NULL
, 0);
6575 bpp
= dst_surface
->resource
.format
->byte_count
;
6576 srcheight
= xsrc
.bottom
- xsrc
.top
;
6577 srcwidth
= xsrc
.right
- xsrc
.left
;
6578 dstheight
= xdst
.bottom
- xdst
.top
;
6579 dstwidth
= xdst
.right
- xdst
.left
;
6580 width
= (xdst
.right
- xdst
.left
) * bpp
;
6582 if (src_format
->flags
& dst_format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
6584 UINT row_block_count
;
6586 if (flags
|| src_surface
== dst_surface
)
6588 FIXME("Only plain blits supported on compressed surfaces.\n");
6593 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
6595 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
6597 WARN("Stretching not supported on compressed surfaces.\n");
6598 hr
= WINED3DERR_INVALIDCALL
;
6605 row_block_count
= (dstwidth
+ dst_format
->block_width
- 1) / dst_format
->block_width
;
6606 for (y
= 0; y
< dstheight
; y
+= dst_format
->block_height
)
6608 memcpy(dbuf
, sbuf
, row_block_count
* dst_format
->block_byte_count
);
6609 dbuf
+= dlock
.Pitch
;
6610 sbuf
+= slock
.Pitch
;
6616 if (dst_rect
&& src_surface
!= dst_surface
)
6619 dbuf
= (BYTE
*)dlock
.pBits
+(xdst
.top
*dlock
.Pitch
)+(xdst
.left
*bpp
);
6621 /* First, all the 'source-less' blits */
6622 if (flags
& WINEDDBLT_COLORFILL
)
6624 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dlock
.Pitch
, fx
->u5
.dwFillColor
);
6625 flags
&= ~WINEDDBLT_COLORFILL
;
6628 if (flags
& WINEDDBLT_DEPTHFILL
)
6630 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6632 if (flags
& WINEDDBLT_ROP
)
6634 /* Catch some degenerate cases here. */
6638 hr
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,0);
6640 case 0xAA0029: /* No-op */
6643 hr
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,~0);
6645 case SRCCOPY
: /* Well, we do that below? */
6648 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx
->dwROP
, fx
->u5
.lpDDSPattern
);
6651 flags
&= ~WINEDDBLT_ROP
;
6653 if (flags
& WINEDDBLT_DDROPS
)
6655 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx
->dwDDROP
, fx
->u5
.lpDDSPattern
);
6657 /* Now the 'with source' blits. */
6661 int sx
, xinc
, sy
, yinc
;
6663 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
6666 if (filter
!= WINED3DTEXF_NONE
&& filter
!= WINED3DTEXF_POINT
6667 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
6669 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6670 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
6673 sbase
= (BYTE
*)slock
.pBits
+(xsrc
.top
*slock
.Pitch
)+xsrc
.left
*bpp
;
6674 xinc
= (srcwidth
<< 16) / dstwidth
;
6675 yinc
= (srcheight
<< 16) / dstheight
;
6679 /* No effects, we can cheat here. */
6680 if (dstwidth
== srcwidth
)
6682 if (dstheight
== srcheight
)
6684 /* No stretching in either direction. This needs to be as
6685 * fast as possible. */
6688 /* Check for overlapping surfaces. */
6689 if (src_surface
!= dst_surface
|| xdst
.top
< xsrc
.top
6690 || xdst
.right
<= xsrc
.left
|| xsrc
.right
<= xdst
.left
)
6692 /* No overlap, or dst above src, so copy from top downwards. */
6693 for (y
= 0; y
< dstheight
; ++y
)
6695 memcpy(dbuf
, sbuf
, width
);
6696 sbuf
+= slock
.Pitch
;
6697 dbuf
+= dlock
.Pitch
;
6700 else if (xdst
.top
> xsrc
.top
)
6702 /* Copy from bottom upwards. */
6703 sbuf
+= (slock
.Pitch
*dstheight
);
6704 dbuf
+= (dlock
.Pitch
*dstheight
);
6705 for (y
= 0; y
< dstheight
; ++y
)
6707 sbuf
-= slock
.Pitch
;
6708 dbuf
-= dlock
.Pitch
;
6709 memcpy(dbuf
, sbuf
, width
);
6714 /* Src and dst overlapping on the same line, use memmove. */
6715 for (y
= 0; y
< dstheight
; ++y
)
6717 memmove(dbuf
, sbuf
, width
);
6718 sbuf
+= slock
.Pitch
;
6719 dbuf
+= dlock
.Pitch
;
6725 /* Stretching in y direction only. */
6726 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6728 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
6729 memcpy(dbuf
, sbuf
, width
);
6730 dbuf
+= dlock
.Pitch
;
6736 /* Stretching in X direction. */
6738 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6740 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
6742 if ((sy
>> 16) == (last_sy
>> 16))
6744 /* This source row is the same as last source row -
6745 * Copy the already stretched row. */
6746 memcpy(dbuf
, dbuf
- dlock
.Pitch
, width
);
6750 #define STRETCH_ROW(type) \
6752 const type *s = (const type *)sbuf; \
6753 type *d = (type *)dbuf; \
6754 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6755 d[x] = s[sx >> 16]; \
6773 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
6777 s
= sbuf
+ 3 * (sx
>> 16);
6778 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
6779 d
[0] = (pixel
) & 0xff;
6780 d
[1] = (pixel
>> 8) & 0xff;
6781 d
[2] = (pixel
>> 16) & 0xff;
6787 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
6788 hr
= WINED3DERR_NOTAVAILABLE
;
6793 dbuf
+= dlock
.Pitch
;
6800 LONG dstyinc
= dlock
.Pitch
, dstxinc
= bpp
;
6801 DWORD keylow
= 0xFFFFFFFF, keyhigh
= 0, keymask
= 0xFFFFFFFF;
6802 DWORD destkeylow
= 0x0, destkeyhigh
= 0xFFFFFFFF, destkeymask
= 0xFFFFFFFF;
6803 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
6805 /* The color keying flags are checked for correctness in ddraw */
6806 if (flags
& WINEDDBLT_KEYSRC
)
6808 keylow
= src_surface
->SrcBltCKey
.dwColorSpaceLowValue
;
6809 keyhigh
= src_surface
->SrcBltCKey
.dwColorSpaceHighValue
;
6811 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
6813 keylow
= fx
->ddckSrcColorkey
.dwColorSpaceLowValue
;
6814 keyhigh
= fx
->ddckSrcColorkey
.dwColorSpaceHighValue
;
6817 if (flags
& WINEDDBLT_KEYDEST
)
6819 /* Destination color keys are taken from the source surface! */
6820 destkeylow
= src_surface
->DestBltCKey
.dwColorSpaceLowValue
;
6821 destkeyhigh
= src_surface
->DestBltCKey
.dwColorSpaceHighValue
;
6823 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
6825 destkeylow
= fx
->ddckDestColorkey
.dwColorSpaceLowValue
;
6826 destkeyhigh
= fx
->ddckDestColorkey
.dwColorSpaceHighValue
;
6835 keymask
= src_format
->red_mask
6836 | src_format
->green_mask
6837 | src_format
->blue_mask
;
6839 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
6842 if (flags
& WINEDDBLT_DDFX
)
6844 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
6847 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
6848 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dlock
.Pitch
);
6849 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
6851 if (fx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
6853 /* I don't think we need to do anything about this flag */
6854 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
6856 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
6859 dTopRight
= dTopLeft
;
6862 dBottomRight
= dBottomLeft
;
6864 dstxinc
= dstxinc
* -1;
6866 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
6869 dTopLeft
= dBottomLeft
;
6872 dTopRight
= dBottomRight
;
6874 dstyinc
= dstyinc
* -1;
6876 if (fx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
6878 /* I don't think we need to do anything about this flag */
6879 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
6881 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
6884 dBottomRight
= dTopLeft
;
6887 dBottomLeft
= dTopRight
;
6889 dstxinc
= dstxinc
* -1;
6890 dstyinc
= dstyinc
* -1;
6892 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
6895 dTopLeft
= dBottomLeft
;
6896 dBottomLeft
= dBottomRight
;
6897 dBottomRight
= dTopRight
;
6902 dstxinc
= dstxinc
* -1;
6904 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
6907 dTopLeft
= dTopRight
;
6908 dTopRight
= dBottomRight
;
6909 dBottomRight
= dBottomLeft
;
6914 dstyinc
= dstyinc
* -1;
6916 if (fx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
6918 /* I don't think we need to do anything about this flag */
6919 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
6922 flags
&= ~(WINEDDBLT_DDFX
);
6925 #define COPY_COLORKEY_FX(type) \
6928 type *d = (type *)dbuf, *dx, tmp; \
6929 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
6931 s = (const type *)(sbase + (sy >> 16) * slock.Pitch); \
6933 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6935 tmp = s[sx >> 16]; \
6936 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
6937 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
6941 dx = (type *)(((BYTE *)dx) + dstxinc); \
6943 d = (type *)(((BYTE *)d) + dstyinc); \
6950 COPY_COLORKEY_FX(BYTE
);
6953 COPY_COLORKEY_FX(WORD
);
6956 COPY_COLORKEY_FX(DWORD
);
6961 BYTE
*d
= dbuf
, *dx
;
6962 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6964 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
6966 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
6968 DWORD pixel
, dpixel
= 0;
6969 s
= sbuf
+ 3 * (sx
>>16);
6970 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
6971 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
6972 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
6973 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
6975 dx
[0] = (pixel
) & 0xff;
6976 dx
[1] = (pixel
>> 8) & 0xff;
6977 dx
[2] = (pixel
>> 16) & 0xff;
6986 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
6987 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
* 8);
6988 hr
= WINED3DERR_NOTAVAILABLE
;
6990 #undef COPY_COLORKEY_FX
6996 if (flags
&& FIXME_ON(d3d_surface
))
6998 FIXME("\tUnsupported flags: %#x.\n", flags
);
7002 wined3d_surface_unmap(dst_surface
);
7003 if (src_surface
&& src_surface
!= dst_surface
)
7004 wined3d_surface_unmap(src_surface
);
7005 /* Release the converted surface, if any. */
7006 if (src_surface
&& src_surface
!= orig_src
)
7007 wined3d_surface_decref(src_surface
);
7012 /* Do not call while under the GL lock. */
7013 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
7014 const RECT
*dst_rect
, const WINED3DCOLORVALUE
*color
)
7016 static const RECT src_rect
;
7019 memset(&BltFx
, 0, sizeof(BltFx
));
7020 BltFx
.dwSize
= sizeof(BltFx
);
7021 BltFx
.u5
.dwFillColor
= wined3d_format_convert_from_float(dst_surface
, color
);
7022 return surface_cpu_blt(dst_surface
, dst_rect
, NULL
, &src_rect
,
7023 WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
7026 /* Do not call while under the GL lock. */
7027 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
7028 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
7030 FIXME("Depth filling not implemented by cpu_blit.\n");
7031 return WINED3DERR_INVALIDCALL
;
7034 const struct blit_shader cpu_blit
= {
7040 cpu_blit_color_fill
,
7041 cpu_blit_depth_fill
,
7044 static HRESULT
surface_init(struct wined3d_surface
*surface
, WINED3DSURFTYPE surface_type
, UINT alignment
,
7045 UINT width
, UINT height
, UINT level
, BOOL lockable
, BOOL discard
, WINED3DMULTISAMPLE_TYPE multisample_type
,
7046 UINT multisample_quality
, struct wined3d_device
*device
, DWORD usage
, enum wined3d_format_id format_id
,
7047 WINED3DPOOL pool
, void *parent
, const struct wined3d_parent_ops
*parent_ops
)
7049 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
7050 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
7051 unsigned int resource_size
;
7054 if (multisample_quality
> 0)
7056 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality
);
7057 multisample_quality
= 0;
7060 /* Quick lockable sanity check.
7061 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7062 * this function is too deep to need to care about things like this.
7063 * Levels need to be checked too, since they all affect what can be done. */
7066 case WINED3DPOOL_SCRATCH
:
7069 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7070 "which are mutually exclusive, setting lockable to TRUE.\n");
7075 case WINED3DPOOL_SYSTEMMEM
:
7077 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7080 case WINED3DPOOL_MANAGED
:
7081 if (usage
& WINED3DUSAGE_DYNAMIC
)
7082 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7085 case WINED3DPOOL_DEFAULT
:
7086 if (lockable
&& !(usage
& (WINED3DUSAGE_DYNAMIC
| WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
7087 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7091 FIXME("Unknown pool %#x.\n", pool
);
7095 if (usage
& WINED3DUSAGE_RENDERTARGET
&& pool
!= WINED3DPOOL_DEFAULT
)
7096 FIXME("Trying to create a render target that isn't in the default pool.\n");
7098 /* FIXME: Check that the format is supported by the device. */
7100 resource_size
= wined3d_format_calculate_size(format
, alignment
, width
, height
);
7102 return WINED3DERR_INVALIDCALL
;
7104 surface
->surface_type
= surface_type
;
7106 switch (surface_type
)
7108 case SURFACE_OPENGL
:
7109 surface
->surface_ops
= &surface_ops
;
7113 surface
->surface_ops
= &gdi_surface_ops
;
7117 ERR("Requested unknown surface implementation %#x.\n", surface_type
);
7118 return WINED3DERR_INVALIDCALL
;
7121 hr
= resource_init(&surface
->resource
, device
, WINED3DRTYPE_SURFACE
, format
,
7122 multisample_type
, multisample_quality
, usage
, pool
, width
, height
, 1,
7123 resource_size
, parent
, parent_ops
, &surface_resource_ops
);
7126 WARN("Failed to initialize resource, returning %#x.\n", hr
);
7130 /* "Standalone" surface. */
7131 surface_set_container(surface
, WINED3D_CONTAINER_NONE
, NULL
);
7133 surface
->texture_level
= level
;
7134 list_init(&surface
->overlays
);
7137 surface
->flags
= SFLAG_NORMCOORD
; /* Default to normalized coords. */
7139 surface
->flags
|= SFLAG_DISCARD
;
7140 if (lockable
|| format_id
== WINED3DFMT_D16_LOCKABLE
)
7141 surface
->flags
|= SFLAG_LOCKABLE
;
7142 /* I'm not sure if this qualifies as a hack or as an optimization. It
7143 * seems reasonable to assume that lockable render targets will get
7144 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7145 * creation. However, the other reason we want to do this is that several
7146 * ddraw applications access surface memory while the surface isn't
7147 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7148 * future locks prevents these from crashing. */
7149 if (lockable
&& (usage
& WINED3DUSAGE_RENDERTARGET
))
7150 surface
->flags
|= SFLAG_DYNLOCK
;
7152 /* Mark the texture as dirty so that it gets loaded first time around. */
7153 surface_add_dirty_rect(surface
, NULL
);
7154 list_init(&surface
->renderbuffers
);
7156 TRACE("surface %p, memory %p, size %u\n",
7157 surface
, surface
->resource
.allocatedMemory
, surface
->resource
.size
);
7159 /* Call the private setup routine */
7160 hr
= surface
->surface_ops
->surface_private_setup(surface
);
7163 ERR("Private setup failed, returning %#x\n", hr
);
7164 surface
->surface_ops
->surface_cleanup(surface
);
7171 HRESULT CDECL
wined3d_surface_create(struct wined3d_device
*device
, UINT width
, UINT height
,
7172 enum wined3d_format_id format_id
, BOOL lockable
, BOOL discard
, UINT level
, DWORD usage
, WINED3DPOOL pool
,
7173 WINED3DMULTISAMPLE_TYPE multisample_type
, DWORD multisample_quality
, WINED3DSURFTYPE surface_type
,
7174 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_surface
**surface
)
7176 struct wined3d_surface
*object
;
7179 TRACE("device %p, width %u, height %u, format %s, lockable %#x, discard %#x, level %u\n",
7180 device
, width
, height
, debug_d3dformat(format_id
), lockable
, discard
, level
);
7181 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7182 surface
, debug_d3dusage(usage
), usage
, debug_d3dpool(pool
), multisample_type
, multisample_quality
);
7183 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", surface_type
, parent
, parent_ops
);
7185 if (surface_type
== SURFACE_OPENGL
&& !device
->adapter
)
7187 ERR("OpenGL surfaces are not available without OpenGL.\n");
7188 return WINED3DERR_NOTAVAILABLE
;
7191 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
7194 ERR("Failed to allocate surface memory.\n");
7195 return WINED3DERR_OUTOFVIDEOMEMORY
;
7198 hr
= surface_init(object
, surface_type
, device
->surface_alignment
, width
, height
, level
, lockable
,
7199 discard
, multisample_type
, multisample_quality
, device
, usage
, format_id
, pool
, parent
, parent_ops
);
7202 WARN("Failed to initialize surface, returning %#x.\n", hr
);
7203 HeapFree(GetProcessHeap(), 0, object
);
7207 TRACE("Created surface %p.\n", object
);