Use Interlocked* functions in AddRef and Release.
[wine/multimedia.git] / dlls / wined3d / surface.c
blobbe5d18fce298131025fa873c998beddc4eef79f7
1 /*
2 * IWineD3DSurface Implementation
4 * Copyright 2002-2005 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"
24 #include "wined3d_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
27 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
29 /* *******************************************
30 IWineD3DSurface IUnknown parts follow
31 ******************************************* */
32 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
34 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
35 WARN("(%p)->(%s,%p) should not be called\n",This,debugstr_guid(riid),ppobj);
36 return E_NOINTERFACE;
39 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
40 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
41 TRACE("(%p) : AddRef increasing from %ld\n", This, This->resource.ref);
42 IUnknown_AddRef(This->resource.parent);
43 return InterlockedIncrement(&This->resource.ref);
46 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
47 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
48 ULONG ref;
49 TRACE("(%p) : Releasing from %ld\n", This, This->resource.ref);
50 ref = InterlockedDecrement(&This->resource.ref);
51 if (ref == 0) {
52 HeapFree(GetProcessHeap(), 0, This->allocatedMemory);
53 IWineD3DDevice_Release((IWineD3DDevice *)This->resource.wineD3DDevice);
54 HeapFree(GetProcessHeap(), 0, This);
55 } else {
56 IUnknown_Release(This->resource.parent); /* Released the reference to the d3dx object */
58 return ref;
61 /* ****************************************************
62 IWineD3DSurface IWineD3DResource parts follow
63 **************************************************** */
64 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
65 return IWineD3DResource_GetDevice((IWineD3DResource *)iface, ppDevice);
68 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
69 return IWineD3DResource_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
72 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
73 return IWineD3DResource_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
76 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
77 return IWineD3DResource_FreePrivateData((IWineD3DResource *)iface, refguid);
80 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
81 return IWineD3DResource_SetPriority((IWineD3DResource *)iface, PriorityNew);
84 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
85 return IWineD3DResource_GetPriority((IWineD3DResource *)iface);
88 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
89 return IWineD3DResource_PreLoad((IWineD3DResource *)iface);
92 D3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
93 return IWineD3DResource_GetType((IWineD3DResource *)iface);
96 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
97 return IWineD3DResource_GetParent((IWineD3DResource *)iface, pParent);
100 /* ******************************************************
101 IWineD3DSurface IWineD3DSurface parts follow
102 ****************************************************** */
104 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface *iface, REFIID riid, void** ppContainer) {
105 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
107 /** From MSDN:
108 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
109 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
110 * GetContainer will return the Direct3D device used to create the surface.
112 WARN("Query of container implementation currently ignores riid\n");
113 *ppContainer = This->container;
114 IUnknown_AddRef((IUnknown *)*ppContainer);
115 TRACE("(%p) : returning %p\n", This, *ppContainer);
116 return D3D_OK;
119 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
120 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
122 TRACE("(%p) : copying into %p\n", This, pDesc);
123 *(pDesc->Format) = This->currentDesc.Format;
124 *(pDesc->Type) = This->currentDesc.Type;
125 *(pDesc->Usage) = This->currentDesc.Usage;
126 *(pDesc->Pool) = This->currentDesc.Pool;
127 *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
128 *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
129 *(pDesc->Width) = This->currentDesc.Width;
130 *(pDesc->Height) = This->currentDesc.Height;
131 return D3D_OK;
134 HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
135 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
137 /* fixme: should we really lock as such? */
138 if (This->inTexture && This->inPBuffer) {
139 FIXME("Warning: Surface is in texture memory or pbuffer\n");
140 This->inTexture = 0;
141 This->inPBuffer = 0;
144 if (FALSE == This->lockable) {
145 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
146 texture regions, and since the destination is an unlockable region we need
147 to tolerate this */
148 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
149 /*return D3DERR_INVALIDCALL; */
152 if (This == This->resource.wineD3DDevice->backBuffer || This == This->resource.wineD3DDevice->renderTarget || This == This->resource.wineD3DDevice->frontBuffer || This->resource.wineD3DDevice->depthStencilBuffer) {
153 if (This == This->resource.wineD3DDevice->backBuffer) {
154 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
155 } else if (This == This->resource.wineD3DDevice->frontBuffer) {
156 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
157 } else if (This == This->resource.wineD3DDevice->renderTarget) {
158 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
159 } else if (This == This->resource.wineD3DDevice->depthStencilBuffer) {
160 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
162 } else {
163 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
166 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
167 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt3/5)
168 ie pitch = (width/4) * bytes per block */
169 if (This->currentDesc.Format == D3DFMT_DXT1) /* DXT1 is 8 bytes per block */
170 pLockedRect->Pitch = (This->currentDesc.Width/4) * 8;
171 else if (This->currentDesc.Format == D3DFMT_DXT3 || This->currentDesc.Format == D3DFMT_DXT5) /* DXT3/5 is 16 bytes per block */
172 pLockedRect->Pitch = (This->currentDesc.Width/4) * 16;
173 else
174 pLockedRect->Pitch = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
176 if (NULL == pRect) {
177 pLockedRect->pBits = This->allocatedMemory;
178 This->lockedRect.left = 0;
179 This->lockedRect.top = 0;
180 This->lockedRect.right = This->currentDesc.Width;
181 This->lockedRect.bottom = This->currentDesc.Height;
182 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);
183 } else {
184 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
186 if (This->currentDesc.Format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
187 pLockedRect->pBits = This->allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel/2));
188 } else {
189 pLockedRect->pBits = This->allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
191 This->lockedRect.left = pRect->left;
192 This->lockedRect.top = pRect->top;
193 This->lockedRect.right = pRect->right;
194 This->lockedRect.bottom = pRect->bottom;
198 if (0 == This->currentDesc.Usage) { /* classic surface */
200 /* Nothing to do ;) */
202 } else if (D3DUSAGE_RENDERTARGET & This->currentDesc.Usage && !(Flags&D3DLOCK_DISCARD)) { /* render surfaces */
204 if (This == This->resource.wineD3DDevice->backBuffer || This == This->resource.wineD3DDevice->renderTarget || This == This->resource.wineD3DDevice->frontBuffer) {
205 GLint prev_store;
206 GLenum prev_read;
208 ENTER_GL();
211 * for render->surface copy begin to begin of allocatedMemory
212 * unlock can be more easy
214 pLockedRect->pBits = This->allocatedMemory;
216 glFlush();
217 vcheckGLcall("glFlush");
218 glGetIntegerv(GL_READ_BUFFER, &prev_read);
219 vcheckGLcall("glIntegerv");
220 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
221 vcheckGLcall("glIntegerv");
223 if (This == This->resource.wineD3DDevice->backBuffer) {
224 glReadBuffer(GL_BACK);
225 } else if (This == This->resource.wineD3DDevice->frontBuffer || This == This->resource.wineD3DDevice->renderTarget) {
226 glReadBuffer(GL_FRONT);
227 } else if (This == This->resource.wineD3DDevice->depthStencilBuffer) {
228 ERR("Stencil Buffer lock unsupported for now\n");
230 vcheckGLcall("glReadBuffer");
233 long j;
234 GLenum format = D3DFmt2GLFmt(This->resource.wineD3DDevice, This->currentDesc.Format);
235 GLenum type = D3DFmt2GLType(This->resource.wineD3DDevice, This->currentDesc.Format);
236 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
237 glReadPixels(This->lockedRect.left,
238 This->lockedRect.bottom - j - 1,
239 This->lockedRect.right - This->lockedRect.left,
241 format,
242 type,
243 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
244 vcheckGLcall("glReadPixels");
248 glReadBuffer(prev_read);
249 vcheckGLcall("glReadBuffer");
251 LEAVE_GL();
253 } else {
254 FIXME("unsupported locking to Rendering surface surf@%p usage(%lu)\n", This, This->currentDesc.Usage);
257 } else if (D3DUSAGE_DEPTHSTENCIL & This->currentDesc.Usage) { /* stencil surfaces */
259 FIXME("TODO stencil depth surface locking surf@%p usage(%lu)\n", This, This->currentDesc.Usage);
261 } else {
262 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->currentDesc.Usage);
265 if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
266 /* Don't dirtify */
267 } else {
269 * Dirtify on lock
270 * as seen in msdn docs
272 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
274 /** Dirtify Container if needed */
275 if ((NULL != This->container) && ((IWineD3DDeviceImpl *)This->container != This->resource.wineD3DDevice)) {
276 IWineD3DBaseTexture_SetDirty((IWineD3DBaseTexture *)This->container, TRUE);
280 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
282 This->locked = TRUE;
283 return D3D_OK;
286 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
287 GLint skipBytes = 0;
288 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
290 if (FALSE == This->locked) {
291 ERR("trying to Unlock an unlocked surf@%p\n", This);
292 return D3DERR_INVALIDCALL;
295 if (This == This->resource.wineD3DDevice->backBuffer || This == This->resource.wineD3DDevice->frontBuffer || This->resource.wineD3DDevice->depthStencilBuffer || This == This->resource.wineD3DDevice->renderTarget) {
296 if (This == This->resource.wineD3DDevice->backBuffer) {
297 TRACE("(%p, backBuffer) : dirtyfied(%d)\n", This, This->Dirty);
298 } else if (This == This->resource.wineD3DDevice->frontBuffer) {
299 TRACE("(%p, frontBuffer) : dirtyfied(%d)\n", This, This->Dirty);
300 } else if (This == This->resource.wineD3DDevice->depthStencilBuffer) {
301 TRACE("(%p, stencilBuffer) : dirtyfied(%d)\n", This, This->Dirty);
302 } else if (This == This->resource.wineD3DDevice->renderTarget) {
303 TRACE("(%p, renderTarget) : dirtyfied(%d)\n", This, This->Dirty);
305 } else {
306 TRACE("(%p) : dirtyfied(%d)\n", This, This->Dirty);
309 if (FALSE == This->Dirty) {
310 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
311 goto unlock_end;
314 if (0 == This->currentDesc.Usage) { /* classic surface */
316 * nothing to do
317 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
319 } else if (D3DUSAGE_RENDERTARGET & This->currentDesc.Usage) { /* render surfaces */
321 if (This == This->resource.wineD3DDevice->backBuffer || This == This->resource.wineD3DDevice->frontBuffer || This == This->resource.wineD3DDevice->renderTarget) {
322 GLint prev_store;
323 GLenum prev_draw;
324 GLint prev_rasterpos[4];
326 ENTER_GL();
328 glFlush();
329 vcheckGLcall("glFlush");
330 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
331 vcheckGLcall("glIntegerv");
332 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
333 vcheckGLcall("glIntegerv");
334 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
335 vcheckGLcall("glIntegerv");
336 glPixelZoom(1.0, -1.0);
337 vcheckGLcall("glPixelZoom");
339 /* glDrawPixels transforms the raster position as though it was a vertex -
340 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
341 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
342 if (!This->resource.wineD3DDevice->last_was_rhw) {
344 double X, Y, height, width, minZ, maxZ;
345 This->resource.wineD3DDevice->last_was_rhw = TRUE;
347 /* Transformed already into viewport coordinates, so we do not need transform
348 matrices. Reset all matrices to identity and leave the default matrix in world
349 mode. */
350 glMatrixMode(GL_MODELVIEW);
351 checkGLcall("glMatrixMode");
352 glLoadIdentity();
353 checkGLcall("glLoadIdentity");
355 glMatrixMode(GL_PROJECTION);
356 checkGLcall("glMatrixMode");
357 glLoadIdentity();
358 checkGLcall("glLoadIdentity");
360 /* Set up the viewport to be full viewport */
361 X = This->resource.wineD3DDevice->stateBlock->viewport.X;
362 Y = This->resource.wineD3DDevice->stateBlock->viewport.Y;
363 height = This->resource.wineD3DDevice->stateBlock->viewport.Height;
364 width = This->resource.wineD3DDevice->stateBlock->viewport.Width;
365 minZ = This->resource.wineD3DDevice->stateBlock->viewport.MinZ;
366 maxZ = This->resource.wineD3DDevice->stateBlock->viewport.MaxZ;
367 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
368 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
369 checkGLcall("glOrtho");
371 /* Window Coord 0 is the middle of the first pixel, so translate by half
372 a pixel (See comment above glTranslate below) */
373 glTranslatef(0.5, 0.5, 0);
374 checkGLcall("glTranslatef(0.5, 0.5, 0)");
377 if (This == This->resource.wineD3DDevice->backBuffer) {
378 glDrawBuffer(GL_BACK);
379 } else if (This == This->resource.wineD3DDevice->frontBuffer || This == This->resource.wineD3DDevice->renderTarget) {
380 glDrawBuffer(GL_FRONT);
382 vcheckGLcall("glDrawBuffer");
384 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
385 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
386 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
388 /* And back buffers are not blended */
389 glDisable(GL_BLEND);
391 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
392 vcheckGLcall("glRasterPos2f");
393 switch (This->currentDesc.Format) {
394 case D3DFMT_R5G6B5:
396 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
397 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->allocatedMemory);
398 vcheckGLcall("glDrawPixels");
400 break;
401 case D3DFMT_R8G8B8:
403 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
404 GL_RGB, GL_UNSIGNED_BYTE, This->allocatedMemory);
405 vcheckGLcall("glDrawPixels");
407 break;
408 case D3DFMT_A8R8G8B8:
410 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
411 vcheckGLcall("glPixelStorei");
412 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
413 GL_BGRA, GL_UNSIGNED_BYTE, This->allocatedMemory);
414 vcheckGLcall("glDrawPixels");
415 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
416 vcheckGLcall("glPixelStorei");
418 break;
419 default:
420 FIXME("Unsupported Format %u in locking func\n", This->currentDesc.Format);
423 glPixelZoom(1.0,1.0);
424 vcheckGLcall("glPixelZoom");
425 glDrawBuffer(prev_draw);
426 vcheckGLcall("glDrawBuffer");
427 glRasterPos3iv(&prev_rasterpos[0]);
428 vcheckGLcall("glRasterPos3iv");
430 /* Reset to previous pack row length / blending state */
431 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
432 if (This->resource.wineD3DDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
434 LEAVE_GL();
436 /** restore clean dirty state */
437 IWineD3DSurface_CleanDirtyRect(iface);
439 } else {
440 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->currentDesc.Usage);
443 } else if (D3DUSAGE_DEPTHSTENCIL & This->currentDesc.Usage) { /* stencil surfaces */
445 if (This == This->resource.wineD3DDevice->depthStencilBuffer) {
446 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->currentDesc.Usage);
447 } else {
448 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->currentDesc.Usage);
451 } else {
452 FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->currentDesc.Usage);
455 unlock_end:
456 This->locked = FALSE;
457 memset(&This->lockedRect, 0, sizeof(RECT));
458 return D3D_OK;
461 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
462 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
463 FIXME("No support for GetDC yet for surface %p\n", This);
464 return D3DERR_INVALIDCALL;
467 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
468 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
469 FIXME("No support for ReleaseDC yet for surface %p\n", This);
470 return D3DERR_INVALIDCALL;
473 /* ******************************************************
474 IWineD3DSurface Internal (No mapping to directx api) parts follow
475 ****************************************************** */
476 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, GLenum gl_target, GLenum gl_level) {
477 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
479 if (This->inTexture)
480 return D3D_OK;
482 if (This->inPBuffer) {
483 ENTER_GL();
485 if (gl_level != 0)
486 FIXME("Surface in texture is only supported for level 0\n");
487 else if (This->currentDesc.Format == D3DFMT_P8 || This->currentDesc.Format == D3DFMT_A8P8 ||
488 This->currentDesc.Format == D3DFMT_DXT1 || This->currentDesc.Format == D3DFMT_DXT3 ||
489 This->currentDesc.Format == D3DFMT_DXT5)
490 FIXME("Format %d not supported\n", This->currentDesc.Format);
491 else {
492 glCopyTexImage2D(gl_target,
494 D3DFmt2GLIntFmt(This->resource.wineD3DDevice,
495 This->currentDesc.Format),
498 This->currentDesc.Width,
499 This->currentDesc.Height,
501 TRACE("Updating target %d\n", gl_target);
502 This->inTexture = TRUE;
504 LEAVE_GL();
505 return D3D_OK;
508 if ((This->currentDesc.Format == D3DFMT_P8 || This->currentDesc.Format == D3DFMT_A8P8) &&
509 !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
511 * wanted a paletted texture and not really support it in HW
512 * so software emulation code begin
514 UINT i;
515 PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
516 VOID* surface = (VOID*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
517 BYTE* dst = (BYTE*) surface;
518 BYTE* src = (BYTE*) This->allocatedMemory;
520 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
521 BYTE color = *src++;
522 *dst++ = pal[color].peRed;
523 *dst++ = pal[color].peGreen;
524 *dst++ = pal[color].peBlue;
525 if (This->currentDesc.Format == D3DFMT_A8P8)
526 *dst++ = pal[color].peFlags;
527 else
528 *dst++ = 0xFF;
531 ENTER_GL();
533 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
534 gl_target,
535 gl_level,
536 GL_RGBA,
537 This->currentDesc.Width,
538 This->currentDesc.Height,
540 GL_RGBA,
541 GL_UNSIGNED_BYTE,
542 surface);
543 glTexImage2D(gl_target,
544 gl_level,
545 GL_RGBA,
546 This->currentDesc.Width,
547 This->currentDesc.Height,
549 GL_RGBA,
550 GL_UNSIGNED_BYTE,
551 surface);
552 checkGLcall("glTexImage2D");
553 HeapFree(GetProcessHeap(), 0, surface);
555 LEAVE_GL();
557 return D3D_OK;
560 if (This->currentDesc.Format == D3DFMT_DXT1 ||
561 This->currentDesc.Format == D3DFMT_DXT3 ||
562 This->currentDesc.Format == D3DFMT_DXT5) {
563 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
564 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
565 gl_target,
566 gl_level,
567 D3DFmt2GLIntFmt(This->resource.wineD3DDevice, This->currentDesc.Format),
568 This->currentDesc.Width,
569 This->currentDesc.Height,
571 This->currentDesc.Size,
572 This->allocatedMemory);
574 ENTER_GL();
576 GL_EXTCALL(glCompressedTexImage2DARB)(gl_target,
577 gl_level,
578 D3DFmt2GLIntFmt(This->resource.wineD3DDevice, This->currentDesc.Format),
579 This->currentDesc.Width,
580 This->currentDesc.Height,
582 This->currentDesc.Size,
583 This->allocatedMemory);
584 checkGLcall("glCommpressedTexTexImage2D");
586 LEAVE_GL();
587 } else {
588 FIXME("Using DXT1/3/5 without advertized support\n");
590 } else {
592 TRACE("Calling glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
593 gl_target,
594 gl_level,
595 debug_d3dformat(This->currentDesc.Format),
596 D3DFmt2GLIntFmt(This->resource.wineD3DDevice, This->currentDesc.Format),
597 This->currentDesc.Width,
598 This->currentDesc.Height,
600 D3DFmt2GLFmt(This->resource.wineD3DDevice, This->currentDesc.Format),
601 D3DFmt2GLType(This->resource.wineD3DDevice, This->currentDesc.Format),
602 This->allocatedMemory);
604 ENTER_GL();
606 glTexImage2D(gl_target,
607 gl_level,
608 D3DFmt2GLIntFmt(This->resource.wineD3DDevice, This->currentDesc.Format),
609 This->currentDesc.Width,
610 This->currentDesc.Height,
612 D3DFmt2GLFmt(This->resource.wineD3DDevice, This->currentDesc.Format),
613 D3DFmt2GLType(This->resource.wineD3DDevice, This->currentDesc.Format),
614 This->allocatedMemory);
615 checkGLcall("glTexImage2D");
617 LEAVE_GL();
619 #if 0
621 static unsigned int gen = 0;
622 char buffer[4096];
623 ++gen;
624 if ((gen % 10) == 0) {
625 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, gl_target, gl_level, gen);
626 IWineD3DSurfaceImpl_SaveSnapshot((LPDIRECT3DSURFACE8) This, buffer);
629 * debugging crash code
630 if (gen == 250) {
631 void** test = NULL;
632 *test = 0;
636 #endif
639 return D3D_OK;
642 #include <errno.h>
643 #include <stdio.h>
644 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
645 FILE* f = NULL;
646 ULONG i;
647 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
649 f = fopen(filename, "w+");
650 if (NULL == f) {
651 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
652 return D3DERR_INVALIDCALL;
655 TRACE("opened %s with format %s\n", filename, debug_d3dformat(This->currentDesc.Format));
657 fprintf(f, "P6\n%u %u\n255\n", This->currentDesc.Width, This->currentDesc.Height);
658 switch (This->currentDesc.Format) {
659 case D3DFMT_X8R8G8B8:
660 case D3DFMT_A8R8G8B8:
662 DWORD color;
663 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
664 color = ((DWORD*) This->allocatedMemory)[i];
665 fputc((color >> 16) & 0xFF, f);
666 fputc((color >> 8) & 0xFF, f);
667 fputc((color >> 0) & 0xFF, f);
670 break;
671 case D3DFMT_R8G8B8:
673 BYTE* color;
674 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
675 color = ((BYTE*) This->allocatedMemory) + (3 * i);
676 fputc((color[0]) & 0xFF, f);
677 fputc((color[1]) & 0xFF, f);
678 fputc((color[2]) & 0xFF, f);
681 break;
682 case D3DFMT_A1R5G5B5:
684 WORD color;
685 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
686 color = ((WORD*) This->allocatedMemory)[i];
687 fputc(((color >> 10) & 0x1F) * 255 / 31, f);
688 fputc(((color >> 5) & 0x1F) * 255 / 31, f);
689 fputc(((color >> 0) & 0x1F) * 255 / 31, f);
692 break;
693 case D3DFMT_A4R4G4B4:
695 WORD color;
696 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
697 color = ((WORD*) This->allocatedMemory)[i];
698 fputc(((color >> 8) & 0x0F) * 255 / 15, f);
699 fputc(((color >> 4) & 0x0F) * 255 / 15, f);
700 fputc(((color >> 0) & 0x0F) * 255 / 15, f);
703 break;
705 case D3DFMT_R5G6B5:
707 WORD color;
708 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
709 color = ((WORD*) This->allocatedMemory)[i];
710 fputc(((color >> 11) & 0x1F) * 255 / 31, f);
711 fputc(((color >> 5) & 0x3F) * 255 / 63, f);
712 fputc(((color >> 0) & 0x1F) * 255 / 31, f);
715 break;
716 default:
717 FIXME("Unimplemented dump mode format(%u,%s)\n", This->currentDesc.Format, debug_d3dformat(This->currentDesc.Format));
719 fclose(f);
720 return D3D_OK;
723 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
724 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
725 This->Dirty = FALSE;
726 This->dirtyRect.left = This->currentDesc.Width;
727 This->dirtyRect.top = This->currentDesc.Height;
728 This->dirtyRect.right = 0;
729 This->dirtyRect.bottom = 0;
730 return D3D_OK;
734 * Slightly inefficient way to handle multiple dirty rects but it works :)
736 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
737 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
738 This->Dirty = TRUE;
739 if (NULL != pDirtyRect) {
740 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
741 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
742 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
743 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
744 } else {
745 This->dirtyRect.left = 0;
746 This->dirtyRect.top = 0;
747 This->dirtyRect.right = This->currentDesc.Width;
748 This->dirtyRect.bottom = This->currentDesc.Height;
750 return D3D_OK;
753 IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
755 IWineD3DSurfaceImpl_QueryInterface,
756 IWineD3DSurfaceImpl_AddRef,
757 IWineD3DSurfaceImpl_Release,
758 IWineD3DSurfaceImpl_GetParent,
759 IWineD3DSurfaceImpl_GetDevice,
760 IWineD3DSurfaceImpl_SetPrivateData,
761 IWineD3DSurfaceImpl_GetPrivateData,
762 IWineD3DSurfaceImpl_FreePrivateData,
763 IWineD3DSurfaceImpl_SetPriority,
764 IWineD3DSurfaceImpl_GetPriority,
765 IWineD3DSurfaceImpl_PreLoad,
766 IWineD3DSurfaceImpl_GetType,
767 IWineD3DSurfaceImpl_GetContainer,
768 IWineD3DSurfaceImpl_GetDesc,
769 IWineD3DSurfaceImpl_LockRect,
770 IWineD3DSurfaceImpl_UnlockRect,
771 IWineD3DSurfaceImpl_GetDC,
772 IWineD3DSurfaceImpl_ReleaseDC,
773 /* Internal use: */
774 IWineD3DSurfaceImpl_CleanDirtyRect,
775 IWineD3DSurfaceImpl_AddDirtyRect,
776 IWineD3DSurfaceImpl_LoadTexture,
777 IWineD3DSurfaceImpl_SaveSnapshot