- use Interlocked* functions in AddRef and Release.
[wine/gsoc_dplay.git] / dlls / d3d8 / surface.c
blob76e042bf5eebc3769eb80fa5521311750166dfa6
1 /*
2 * IDirect3DSurface8 implementation
4 * Copyright 2002-2004 Jason Edmeades
5 * Copyright 2002-2003 Raphael Junqueira
6 * Copyright 2004 Christian Costa
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
25 #include <stdarg.h>
26 #include <stdio.h>
28 #define COBJMACROS
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winuser.h"
35 #include "wingdi.h"
36 #include "wine/debug.h"
38 #include "d3d8_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
42 /* IDirect3DVolume IUnknown parts follow: */
43 HRESULT WINAPI IDirect3DSurface8Impl_QueryInterface(LPDIRECT3DSURFACE8 iface,REFIID riid,LPVOID *ppobj)
45 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
47 if (IsEqualGUID(riid, &IID_IUnknown)
48 || IsEqualGUID(riid, &IID_IDirect3DSurface8)) {
49 IDirect3DSurface8Impl_AddRef(iface);
50 *ppobj = This;
51 return D3D_OK;
54 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
55 return E_NOINTERFACE;
58 ULONG WINAPI IDirect3DSurface8Impl_AddRef(LPDIRECT3DSURFACE8 iface) {
59 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
60 ULONG ref = InterlockedIncrement(&This->ref);
62 TRACE("(%p) : AddRef from %ld\n", This, ref - 1);
64 return ref;
67 ULONG WINAPI IDirect3DSurface8Impl_Release(LPDIRECT3DSURFACE8 iface) {
68 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
69 ULONG ref = InterlockedDecrement(&This->ref);
71 TRACE("(%p) : ReleaseRef to %ld\n", This, ref);
73 if (ref == 0) {
74 HeapFree(GetProcessHeap(), 0, This->allocatedMemory);
75 HeapFree(GetProcessHeap(), 0, This);
77 return ref;
80 /* IDirect3DSurface8: */
81 HRESULT WINAPI IDirect3DSurface8Impl_GetDevice(LPDIRECT3DSURFACE8 iface, IDirect3DDevice8** ppDevice) {
82 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
83 TRACE("(%p) : returning %p\n", This, This->Device);
84 *ppDevice = (LPDIRECT3DDEVICE8) This->Device;
85 /**
86 * Note Calling this method will increase the internal reference count
87 * on the IDirect3DDevice8 interface.
89 IDirect3DDevice8Impl_AddRef(*ppDevice);
90 return D3D_OK;
93 HRESULT WINAPI IDirect3DSurface8Impl_SetPrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
94 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
95 FIXME("(%p) : stub\n", This);
96 return D3D_OK;
99 HRESULT WINAPI IDirect3DSurface8Impl_GetPrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
100 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
101 FIXME("(%p) : stub\n", This);
102 return D3D_OK;
105 HRESULT WINAPI IDirect3DSurface8Impl_FreePrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid) {
106 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
107 FIXME("(%p) : stub\n", This);
108 return D3D_OK;
111 HRESULT WINAPI IDirect3DSurface8Impl_GetContainer(LPDIRECT3DSURFACE8 iface, REFIID riid, void** ppContainer) {
112 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
113 HRESULT res;
114 res = IUnknown_QueryInterface(This->Container, riid, ppContainer);
115 if (E_NOINTERFACE == res) {
117 * If the surface is created using CreateImageSurface, CreateRenderTarget,
118 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
119 * GetContainer will return the Direct3D device used to create the surface.
121 res = IUnknown_QueryInterface(This->Container, &IID_IDirect3DDevice8, ppContainer);
123 TRACE("(%p) : returning %p\n", This, *ppContainer);
124 return res;
127 HRESULT WINAPI IDirect3DSurface8Impl_GetDesc(LPDIRECT3DSURFACE8 iface, D3DSURFACE_DESC *pDesc) {
128 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
130 TRACE("(%p) : copying into %p\n", This, pDesc);
131 memcpy(pDesc, &This->myDesc, sizeof(D3DSURFACE_DESC));
132 return D3D_OK;
135 HRESULT WINAPI IDirect3DSurface8Impl_LockRect(LPDIRECT3DSURFACE8 iface, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
136 HRESULT hr;
137 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
139 /* fixme: should we really lock as such? */
140 if (This->inTexture && This->inPBuffer) {
141 FIXME("Warning: Surface is in texture memory or pbuffer\n");
142 This->inTexture = 0;
143 This->inPBuffer = 0;
146 if (FALSE == This->lockable) {
147 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
148 texture regions, and since the destination is an unlockable region we need
149 to tolerate this */
150 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
151 /*return D3DERR_INVALIDCALL; */
154 if (This == This->Device->backBuffer || This == This->Device->renderTarget || This == This->Device->frontBuffer || This->Device->depthStencilBuffer) {
155 if (This == This->Device->backBuffer) {
156 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
157 } else if (This == This->Device->frontBuffer) {
158 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
159 } else if (This == This->Device->renderTarget) {
160 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
161 } else if (This == This->Device->depthStencilBuffer) {
162 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
164 } else {
165 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
168 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
169 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt3/5)
170 ie pitch = (width/4) * bytes per block */
171 if (This->myDesc.Format == D3DFMT_DXT1) /* DXT1 is 8 bytes per block */
172 pLockedRect->Pitch = (This->myDesc.Width/4) * 8;
173 else if (This->myDesc.Format == D3DFMT_DXT3 || This->myDesc.Format == D3DFMT_DXT5) /* DXT3/5 is 16 bytes per block */
174 pLockedRect->Pitch = (This->myDesc.Width/4) * 16;
175 else
176 pLockedRect->Pitch = This->bytesPerPixel * This->myDesc.Width; /* Bytes / row */
178 if (NULL == pRect) {
179 pLockedRect->pBits = This->allocatedMemory;
180 This->lockedRect.left = 0;
181 This->lockedRect.top = 0;
182 This->lockedRect.right = This->myDesc.Width;
183 This->lockedRect.bottom = This->myDesc.Height;
184 TRACE("Locked Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
185 } else {
186 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
188 if (This->myDesc.Format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
189 pLockedRect->pBits = This->allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel/2));
190 } else {
191 pLockedRect->pBits = This->allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
193 This->lockedRect.left = pRect->left;
194 This->lockedRect.top = pRect->top;
195 This->lockedRect.right = pRect->right;
196 This->lockedRect.bottom = pRect->bottom;
200 if (0 == This->myDesc.Usage) { /* classic surface */
202 /* Nothing to do ;) */
204 } else if (D3DUSAGE_RENDERTARGET & This->myDesc.Usage && !(Flags&D3DLOCK_DISCARD)) { /* render surfaces */
206 if (This == This->Device->backBuffer || This == This->Device->renderTarget || This == This->Device->frontBuffer) {
207 GLint prev_store;
208 GLenum prev_read;
210 ENTER_GL();
213 * for render->surface copy begin to begin of allocatedMemory
214 * unlock can be more easy
216 pLockedRect->pBits = This->allocatedMemory;
218 glFlush();
219 vcheckGLcall("glFlush");
220 glGetIntegerv(GL_READ_BUFFER, &prev_read);
221 vcheckGLcall("glIntegerv");
222 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
223 vcheckGLcall("glIntegerv");
225 if (This == This->Device->backBuffer) {
226 glReadBuffer(GL_BACK);
227 } else if (This == This->Device->frontBuffer || This == This->Device->renderTarget) {
228 glReadBuffer(GL_FRONT);
229 } else if (This == This->Device->depthStencilBuffer) {
230 ERR("Stencil Buffer lock unsupported for now\n");
232 vcheckGLcall("glReadBuffer");
235 long j;
236 GLenum format = D3DFmt2GLFmt(This->Device, This->myDesc.Format);
237 GLenum type = D3DFmt2GLType(This->Device, This->myDesc.Format);
238 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
239 glReadPixels(This->lockedRect.left,
240 This->lockedRect.bottom - j - 1,
241 This->lockedRect.right - This->lockedRect.left,
243 format,
244 type,
245 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
246 vcheckGLcall("glReadPixels");
250 glReadBuffer(prev_read);
251 vcheckGLcall("glReadBuffer");
253 LEAVE_GL();
255 } else {
256 FIXME("unsupported locking to Rendering surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
259 } else if (D3DUSAGE_DEPTHSTENCIL & This->myDesc.Usage) { /* stencil surfaces */
261 FIXME("TODO stencil depth surface locking surf@%p usage(%lu)\n", This, This->myDesc.Usage);
263 } else {
264 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
267 if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
268 /* Don't dirtify */
269 } else {
271 * Dirtify on lock
272 * as seen in msdn docs
274 IDirect3DSurface8Impl_AddDirtyRect(iface, &This->lockedRect);
276 /** Dirtify Container if needed */
277 if (NULL != This->Container) {
278 IDirect3DBaseTexture8* cont = NULL;
279 hr = IUnknown_QueryInterface(This->Container, &IID_IDirect3DBaseTexture8, (void**) &cont);
281 if (SUCCEEDED(hr) && NULL != cont) {
282 IDirect3DBaseTexture8Impl_SetDirty(cont, TRUE);
283 IDirect3DBaseTexture8_Release(cont);
284 cont = NULL;
289 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
291 This->locked = TRUE;
292 return D3D_OK;
295 HRESULT WINAPI IDirect3DSurface8Impl_UnlockRect(LPDIRECT3DSURFACE8 iface) {
296 GLint skipBytes = 0;
297 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
299 if (FALSE == This->locked) {
300 ERR("trying to Unlock an unlocked surf@%p\n", This);
301 return D3DERR_INVALIDCALL;
304 if (This == This->Device->backBuffer || This == This->Device->frontBuffer || This->Device->depthStencilBuffer || This == This->Device->renderTarget) {
305 if (This == This->Device->backBuffer) {
306 TRACE("(%p, backBuffer) : dirtyfied(%d)\n", This, This->Dirty);
307 } else if (This == This->Device->frontBuffer) {
308 TRACE("(%p, frontBuffer) : dirtyfied(%d)\n", This, This->Dirty);
309 } else if (This == This->Device->depthStencilBuffer) {
310 TRACE("(%p, stencilBuffer) : dirtyfied(%d)\n", This, This->Dirty);
311 } else if (This == This->Device->renderTarget) {
312 TRACE("(%p, renderTarget) : dirtyfied(%d)\n", This, This->Dirty);
314 } else {
315 TRACE("(%p) : dirtyfied(%d)\n", This, This->Dirty);
318 if (FALSE == This->Dirty) {
319 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
320 goto unlock_end;
323 if (0 == This->myDesc.Usage) { /* classic surface */
325 * nothing to do
326 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
328 } else if (D3DUSAGE_RENDERTARGET & This->myDesc.Usage) { /* render surfaces */
330 if (This == This->Device->backBuffer || This == This->Device->frontBuffer || This == This->Device->renderTarget) {
331 GLint prev_store;
332 GLenum prev_draw;
333 GLint prev_rasterpos[4];
335 ENTER_GL();
337 glFlush();
338 vcheckGLcall("glFlush");
339 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
340 vcheckGLcall("glIntegerv");
341 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
342 vcheckGLcall("glIntegerv");
343 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
344 vcheckGLcall("glIntegerv");
345 glPixelZoom(1.0, -1.0);
346 vcheckGLcall("glPixelZoom");
348 /* glDrawPixels transforms the raster position as though it was a vertex -
349 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
350 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
351 if (!This->Device->last_was_rhw) {
353 double X, Y, height, width, minZ, maxZ;
354 This->Device->last_was_rhw = TRUE;
356 /* Transformed already into viewport coordinates, so we do not need transform
357 matrices. Reset all matrices to identity and leave the default matrix in world
358 mode. */
359 glMatrixMode(GL_MODELVIEW);
360 checkGLcall("glMatrixMode");
361 glLoadIdentity();
362 checkGLcall("glLoadIdentity");
364 glMatrixMode(GL_PROJECTION);
365 checkGLcall("glMatrixMode");
366 glLoadIdentity();
367 checkGLcall("glLoadIdentity");
369 /* Set up the viewport to be full viewport */
370 X = This->Device->StateBlock->viewport.X;
371 Y = This->Device->StateBlock->viewport.Y;
372 height = This->Device->StateBlock->viewport.Height;
373 width = This->Device->StateBlock->viewport.Width;
374 minZ = This->Device->StateBlock->viewport.MinZ;
375 maxZ = This->Device->StateBlock->viewport.MaxZ;
376 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
377 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
378 checkGLcall("glOrtho");
380 /* Window Coord 0 is the middle of the first pixel, so translate by half
381 a pixel (See comment above glTranslate below) */
382 glTranslatef(0.5, 0.5, 0);
383 checkGLcall("glTranslatef(0.5, 0.5, 0)");
386 if (This == This->Device->backBuffer) {
387 glDrawBuffer(GL_BACK);
388 } else if (This == This->Device->frontBuffer || This == This->Device->renderTarget) {
389 glDrawBuffer(GL_FRONT);
391 vcheckGLcall("glDrawBuffer");
393 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
394 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
395 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->myDesc.Width);
397 /* And back buffers are not blended */
398 glDisable(GL_BLEND);
400 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
401 vcheckGLcall("glRasterPos2f");
402 switch (This->myDesc.Format) {
403 case D3DFMT_R5G6B5:
405 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
406 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->allocatedMemory);
407 vcheckGLcall("glDrawPixels");
409 break;
410 case D3DFMT_R8G8B8:
412 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
413 GL_RGB, GL_UNSIGNED_BYTE, This->allocatedMemory);
414 vcheckGLcall("glDrawPixels");
416 break;
417 case D3DFMT_A8R8G8B8:
419 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
420 vcheckGLcall("glPixelStorei");
421 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
422 GL_BGRA, GL_UNSIGNED_BYTE, This->allocatedMemory);
423 vcheckGLcall("glDrawPixels");
424 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
425 vcheckGLcall("glPixelStorei");
427 break;
428 default:
429 FIXME("Unsupported Format %u in locking func\n", This->myDesc.Format);
432 glPixelZoom(1.0,1.0);
433 vcheckGLcall("glPixelZoom");
434 glDrawBuffer(prev_draw);
435 vcheckGLcall("glDrawBuffer");
436 glRasterPos3iv(&prev_rasterpos[0]);
437 vcheckGLcall("glRasterPos3iv");
439 /* Reset to previous pack row length / blending state */
440 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
441 if (This->Device->StateBlock->renderstate[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
443 LEAVE_GL();
445 /** restore clean dirty state */
446 IDirect3DSurface8Impl_CleanDirtyRect(iface);
448 } else {
449 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
452 } else if (D3DUSAGE_DEPTHSTENCIL & This->myDesc.Usage) { /* stencil surfaces */
454 if (This == This->Device->depthStencilBuffer) {
455 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->myDesc.Usage);
456 } else {
457 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
460 } else {
461 FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
464 unlock_end:
465 This->locked = FALSE;
466 memset(&This->lockedRect, 0, sizeof(RECT));
467 return D3D_OK;
471 IDirect3DSurface8Vtbl Direct3DSurface8_Vtbl =
473 IDirect3DSurface8Impl_QueryInterface,
474 IDirect3DSurface8Impl_AddRef,
475 IDirect3DSurface8Impl_Release,
476 IDirect3DSurface8Impl_GetDevice,
477 IDirect3DSurface8Impl_SetPrivateData,
478 IDirect3DSurface8Impl_GetPrivateData,
479 IDirect3DSurface8Impl_FreePrivateData,
480 IDirect3DSurface8Impl_GetContainer,
481 IDirect3DSurface8Impl_GetDesc,
482 IDirect3DSurface8Impl_LockRect,
483 IDirect3DSurface8Impl_UnlockRect,
487 HRESULT WINAPI IDirect3DSurface8Impl_LoadTexture(LPDIRECT3DSURFACE8 iface, UINT gl_target, UINT gl_level) {
488 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
490 if (This->inTexture)
491 return D3D_OK;
492 if (This->inPBuffer) {
493 ENTER_GL();
494 if (gl_level != 0)
495 FIXME("Surface in texture is only supported for level 0\n");
496 else if (This->myDesc.Format == D3DFMT_P8 || This->myDesc.Format == D3DFMT_A8P8 ||
497 This->myDesc.Format == D3DFMT_DXT1 || This->myDesc.Format == D3DFMT_DXT3 ||
498 This->myDesc.Format == D3DFMT_DXT5)
499 FIXME("Format %d not supported\n", This->myDesc.Format);
500 else {
501 glCopyTexImage2D(gl_target,
503 D3DFmt2GLIntFmt(This->Device,
504 This->myDesc.Format),
506 0,/*This->surfaces[j][i]->myDesc.Height-1,*/
507 This->myDesc.Width,
508 This->myDesc.Height,
510 TRACE("Updating target %d\n", gl_target);
511 This->inTexture = TRUE;
513 LEAVE_GL();
514 return D3D_OK;
517 if ((This->myDesc.Format == D3DFMT_P8 || This->myDesc.Format == D3DFMT_A8P8) &&
518 !GL_SUPPORT_DEV(EXT_PALETTED_TEXTURE, This->Device)) {
520 * wanted a paletted texture and not really support it in HW
521 * so software emulation code begin
523 UINT i;
524 PALETTEENTRY* pal = This->Device->palettes[This->Device->currentPalette];
525 VOID* surface = (VOID*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->myDesc.Width * This->myDesc.Height * sizeof(DWORD));
526 BYTE* dst = (BYTE*) surface;
527 BYTE* src = (BYTE*) This->allocatedMemory;
529 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
530 BYTE color = *src++;
531 *dst++ = pal[color].peRed;
532 *dst++ = pal[color].peGreen;
533 *dst++ = pal[color].peBlue;
534 if (This->myDesc.Format == D3DFMT_A8P8)
535 *dst++ = pal[color].peFlags;
536 else
537 *dst++ = 0xFF;
540 ENTER_GL();
542 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
543 gl_target,
544 gl_level,
545 GL_RGBA,
546 This->myDesc.Width,
547 This->myDesc.Height,
549 GL_RGBA,
550 GL_UNSIGNED_BYTE,
551 surface);
552 glTexImage2D(gl_target,
553 gl_level,
554 GL_RGBA,
555 This->myDesc.Width,
556 This->myDesc.Height,
558 GL_RGBA,
559 GL_UNSIGNED_BYTE,
560 surface);
561 checkGLcall("glTexImage2D");
562 HeapFree(GetProcessHeap(), 0, surface);
564 LEAVE_GL();
566 return D3D_OK;
569 if (This->myDesc.Format == D3DFMT_DXT1 ||
570 This->myDesc.Format == D3DFMT_DXT3 ||
571 This->myDesc.Format == D3DFMT_DXT5) {
572 if (GL_SUPPORT_DEV(EXT_TEXTURE_COMPRESSION_S3TC, This->Device)) {
573 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
574 gl_target,
575 gl_level,
576 D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
577 This->myDesc.Width,
578 This->myDesc.Height,
580 This->myDesc.Size,
581 This->allocatedMemory);
583 ENTER_GL();
585 GL_EXTCALL_DEV(glCompressedTexImage2DARB, This->Device)(gl_target,
586 gl_level,
587 D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
588 This->myDesc.Width,
589 This->myDesc.Height,
591 This->myDesc.Size,
592 This->allocatedMemory);
593 checkGLcall("glCommpressedTexTexImage2D");
595 LEAVE_GL();
596 } else {
597 FIXME("Using DXT1/3/5 without advertized support\n");
599 } else {
601 TRACE("Calling glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
602 gl_target,
603 gl_level,
604 debug_d3dformat(This->myDesc.Format),
605 D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
606 This->myDesc.Width,
607 This->myDesc.Height,
609 D3DFmt2GLFmt(This->Device, This->myDesc.Format),
610 D3DFmt2GLType(This->Device, This->myDesc.Format),
611 This->allocatedMemory);
613 ENTER_GL();
615 glTexImage2D(gl_target,
616 gl_level,
617 D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
618 This->myDesc.Width,
619 This->myDesc.Height,
621 D3DFmt2GLFmt(This->Device, This->myDesc.Format),
622 D3DFmt2GLType(This->Device, This->myDesc.Format),
623 This->allocatedMemory);
624 checkGLcall("glTexImage2D");
626 LEAVE_GL();
628 #if 0
630 static unsigned int gen = 0;
631 char buffer[4096];
632 ++gen;
633 if ((gen % 10) == 0) {
634 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, gl_target, gl_level, gen);
635 IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This, buffer);
638 * debugging crash code
639 if (gen == 250) {
640 void** test = NULL;
641 *test = 0;
645 #endif
648 return D3D_OK;
651 #include <errno.h>
652 HRESULT WINAPI IDirect3DSurface8Impl_SaveSnapshot(LPDIRECT3DSURFACE8 iface, const char* filename) {
653 FILE* f = NULL;
654 ULONG i;
655 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
657 f = fopen(filename, "w+");
658 if (NULL == f) {
659 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
660 return D3DERR_INVALIDCALL;
663 TRACE("opened %s with format %s\n", filename, debug_d3dformat(This->myDesc.Format));
665 fprintf(f, "P6\n%u %u\n255\n", This->myDesc.Width, This->myDesc.Height);
666 switch (This->myDesc.Format) {
667 case D3DFMT_X8R8G8B8:
668 case D3DFMT_A8R8G8B8:
670 DWORD color;
671 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
672 color = ((DWORD*) This->allocatedMemory)[i];
673 fputc((color >> 16) & 0xFF, f);
674 fputc((color >> 8) & 0xFF, f);
675 fputc((color >> 0) & 0xFF, f);
678 break;
679 case D3DFMT_R8G8B8:
681 BYTE* color;
682 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
683 color = ((BYTE*) This->allocatedMemory) + (3 * i);
684 fputc((color[0]) & 0xFF, f);
685 fputc((color[1]) & 0xFF, f);
686 fputc((color[2]) & 0xFF, f);
689 break;
690 case D3DFMT_A1R5G5B5:
692 WORD color;
693 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
694 color = ((WORD*) This->allocatedMemory)[i];
695 fputc(((color >> 10) & 0x1F) * 255 / 31, f);
696 fputc(((color >> 5) & 0x1F) * 255 / 31, f);
697 fputc(((color >> 0) & 0x1F) * 255 / 31, f);
700 break;
701 case D3DFMT_A4R4G4B4:
703 WORD color;
704 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
705 color = ((WORD*) This->allocatedMemory)[i];
706 fputc(((color >> 8) & 0x0F) * 255 / 15, f);
707 fputc(((color >> 4) & 0x0F) * 255 / 15, f);
708 fputc(((color >> 0) & 0x0F) * 255 / 15, f);
711 break;
713 case D3DFMT_R5G6B5:
715 WORD color;
716 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
717 color = ((WORD*) This->allocatedMemory)[i];
718 fputc(((color >> 11) & 0x1F) * 255 / 31, f);
719 fputc(((color >> 5) & 0x3F) * 255 / 63, f);
720 fputc(((color >> 0) & 0x1F) * 255 / 31, f);
723 break;
724 default:
725 FIXME("Unimplemented dump mode format(%u,%s)\n", This->myDesc.Format, debug_d3dformat(This->myDesc.Format));
727 fclose(f);
728 return D3D_OK;
731 HRESULT WINAPI IDirect3DSurface8Impl_CleanDirtyRect(LPDIRECT3DSURFACE8 iface) {
732 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
733 This->Dirty = FALSE;
734 This->dirtyRect.left = This->myDesc.Width;
735 This->dirtyRect.top = This->myDesc.Height;
736 This->dirtyRect.right = 0;
737 This->dirtyRect.bottom = 0;
738 return D3D_OK;
742 * Raphael:
743 * very stupid way to handle multiple dirty rects but it works :)
745 extern HRESULT WINAPI IDirect3DSurface8Impl_AddDirtyRect(LPDIRECT3DSURFACE8 iface, CONST RECT* pDirtyRect) {
746 IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
747 This->Dirty = TRUE;
748 if (NULL != pDirtyRect) {
749 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
750 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
751 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
752 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
753 } else {
754 This->dirtyRect.left = 0;
755 This->dirtyRect.top = 0;
756 This->dirtyRect.right = This->myDesc.Width;
757 This->dirtyRect.bottom = This->myDesc.Height;
759 return D3D_OK;