static HRESULT WINAPI IWineD3DVolumeImpl_LoadTexture(IWineD3DVolume *iface, GLenum gl_level) { IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format); if(GL_SUPPORT(EXT_TEXTURE3D)) { TRACE("Calling glTexImage3D %x level=%d, intfmt=%x, w=%d, h=%d,d=%d, 0=%d, glFmt=%x, glType=%x, Mem=%p\n", GL_TEXTURE_3D, gl_level, formatEntry->glInternal, This->currentDesc.Width, This->currentDesc.Height, This->currentDesc.Depth, 0, formatEntry->glFormat, formatEntry->glType, This->resource.allocatedMemory); GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, gl_level, formatEntry->glInternal, This->currentDesc.Width, This->currentDesc.Height, This->currentDesc.Depth, 0, formatEntry->glFormat, formatEntry->glType, This->resource.allocatedMemory)); checkGLcall("glTexImage3D"); } else WARN("This OpenGL implementation doesn't support 3D textures\n"); return WINED3D_OK; }
HRESULT volumetexture_init(IWineD3DVolumeTextureImpl *texture, UINT width, UINT height, UINT depth, UINT levels, IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format, WINED3DPOOL pool, IUnknown *parent, const struct wined3d_parent_ops *parent_ops #ifdef VBOX_WITH_WDDM , HANDLE *shared_handle , void **pavClientMem #endif ) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, gl_info); UINT tmp_w, tmp_h, tmp_d; unsigned int i; HRESULT hr; #ifdef VBOX_WITH_WDDM if (shared_handle) { ERR("shared handle support for volume textures not impemented yet, ignoring!"); } #endif /* TODO: It should only be possible to create textures for formats * that are reported as supported. */ if (WINED3DFMT_UNKNOWN >= format) { WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture); return WINED3DERR_INVALIDCALL; } if (!gl_info->supported[EXT_TEXTURE3D]) { WARN("(%p) : Texture cannot be created - no volume texture support.\n", texture); return WINED3DERR_INVALIDCALL; } /* Calculate levels for mip mapping. */ if (usage & WINED3DUSAGE_AUTOGENMIPMAP) { if (!gl_info->supported[SGIS_GENERATE_MIPMAP]) { WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } if (levels > 1) { WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } else if (!levels) { levels = wined3d_log2i(max(max(width, height), depth)) + 1; TRACE("Calculated levels = %u.\n", levels); } texture->lpVtbl = &IWineD3DVolumeTexture_Vtbl; hr = basetexture_init((IWineD3DBaseTextureImpl *)texture, levels, WINED3DRTYPE_VOLUMETEXTURE, device, 0, usage, format_desc, pool, parent, parent_ops #ifdef VBOX_WITH_WDDM , shared_handle, pavClientMem #endif ); if (FAILED(hr)) { WARN("Failed to initialize basetexture, returning %#x.\n", hr); return hr; } /* Is NP2 support for volumes needed? */ texture->baseTexture.pow2Matrix[0] = 1.0f; texture->baseTexture.pow2Matrix[5] = 1.0f; texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; /* Generate all the surfaces. */ tmp_w = width; tmp_h = height; tmp_d = depth; for (i = 0; i < texture->baseTexture.levels; ++i) { /* Create the volume. */ #ifdef VBOX_WITH_WDDM hr = IWineD3DDeviceParent_CreateVolume(device->device_parent, parent, tmp_w, tmp_h, tmp_d, format, pool, usage, &texture->volumes[i] , shared_handle, pavClientMem ? pavClientMem[i] : NULL); #else hr = IWineD3DDeviceParent_CreateVolume(device->device_parent, parent, tmp_w, tmp_h, tmp_d, format, pool, usage, &texture->volumes[i]); #endif if (FAILED(hr)) { ERR("Creating a volume for the volume texture failed, hr %#x.\n", hr); texture->volumes[i] = NULL; volumetexture_cleanup(texture); return hr; } /* Set its container to this texture. */ IWineD3DVolume_SetContainer(texture->volumes[i], (IWineD3DBase *)texture); /* Calculate the next mipmap level. */ tmp_w = max(1, tmp_w >> 1); tmp_h = max(1, tmp_h >> 1); tmp_d = max(1, tmp_d >> 1); } texture->baseTexture.internal_preload = volumetexture_internal_preload; return WINED3D_OK; }
HRESULT swapchain_init(IWineD3DSwapChainImpl *swapchain, WINED3DSURFTYPE surface_type, IWineD3DDeviceImpl *device, WINED3DPRESENT_PARAMETERS *present_parameters, IUnknown *parent) { const struct wined3d_adapter *adapter = device->adapter; const struct wined3d_format_desc *format_desc; BOOL displaymode_set = FALSE; WINED3DDISPLAYMODE mode; RECT client_rect; HWND window = NULL; #ifdef VBOX_WITH_WDDM IWineD3DSwapChainImpl *overridenSwapchain = NULL; HDC hDC = NULL; #endif HRESULT hr; UINT i; if (present_parameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) { ERR("The application requested %u back buffers, this is not supported.\n", present_parameters->BackBufferCount); return WINED3DERR_INVALIDCALL; } if (present_parameters->BackBufferCount > 1) { FIXME("The application requested more than one back buffer, this is not properly supported.\n" "Please configure the application to use double buffering (1 back buffer) if possible.\n"); } switch (surface_type) { case SURFACE_GDI: swapchain->lpVtbl = &IWineGDISwapChain_Vtbl; break; case SURFACE_OPENGL: swapchain->lpVtbl = &IWineD3DSwapChain_Vtbl; break; case SURFACE_UNKNOWN: FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain.\n"); return WINED3DERR_INVALIDCALL; } #ifdef VBOX_WITH_WDDM if (present_parameters->hDeviceWindow) { overridenSwapchain = swapchain_find(device, present_parameters->hDeviceWindow); if (!overridenSwapchain) { ERR("invalid window handle supplied"); return E_FAIL; } window = overridenSwapchain->win_handle; hDC = overridenSwapchain->hDC; } else { hr = VBoxExtWndCreate(present_parameters->BackBufferWidth, present_parameters->BackBufferHeight, &window, &hDC); if (FAILED(hr)) { ERR("VBoxExtWndCreate failed, hr 0x%x", hr); return hr; } } Assert(window); Assert(hDC); present_parameters->hDeviceWindow = window; #else window = present_parameters->hDeviceWindow ? present_parameters->hDeviceWindow : device->createParms.hFocusWindow; #endif swapchain->device = device; swapchain->parent = parent; swapchain->ref = 1; swapchain->win_handle = window; #ifndef VBOX_WITH_WDDM swapchain->device_window = window; #else Assert(window); swapchain->hDC = hDC; swapchain->presentRt = NULL; #endif if (!present_parameters->Windowed && window) { swapchain_setup_fullscreen_window(swapchain, present_parameters->BackBufferWidth, present_parameters->BackBufferHeight); } IWineD3D_GetAdapterDisplayMode(device->wined3d, adapter->ordinal, &mode); swapchain->orig_width = mode.Width; swapchain->orig_height = mode.Height; swapchain->orig_fmt = mode.Format; format_desc = getFormatDescEntry(mode.Format, &adapter->gl_info); #ifndef VBOX_WITH_WDDM GetClientRect(window, &client_rect); #else client_rect.left = 0; client_rect.top = 0; client_rect.right = present_parameters->BackBufferWidth; client_rect.bottom = present_parameters->BackBufferHeight; #endif if (present_parameters->Windowed && (!present_parameters->BackBufferWidth || !present_parameters->BackBufferHeight || present_parameters->BackBufferFormat == WINED3DFMT_UNKNOWN)) { if (!present_parameters->BackBufferWidth) { present_parameters->BackBufferWidth = client_rect.right; TRACE("Updating width to %u.\n", present_parameters->BackBufferWidth); } if (!present_parameters->BackBufferHeight) { present_parameters->BackBufferHeight = client_rect.bottom; TRACE("Updating height to %u.\n", present_parameters->BackBufferHeight); } if (present_parameters->BackBufferFormat == WINED3DFMT_UNKNOWN) { present_parameters->BackBufferFormat = swapchain->orig_fmt; TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->orig_fmt)); } } swapchain->presentParms = *present_parameters; if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && present_parameters->BackBufferCount && (present_parameters->BackBufferWidth != client_rect.right || present_parameters->BackBufferHeight != client_rect.bottom)) { TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u.\n", present_parameters->BackBufferWidth, present_parameters->BackBufferHeight, client_rect.right, client_rect.bottom); swapchain->render_to_fbo = TRUE; } TRACE("Creating front buffer.\n"); hr = IWineD3DDeviceParent_CreateRenderTarget(device->device_parent, parent, swapchain->presentParms.BackBufferWidth, swapchain->presentParms.BackBufferHeight, swapchain->presentParms.BackBufferFormat, swapchain->presentParms.MultiSampleType, swapchain->presentParms.MultiSampleQuality, TRUE /* Lockable */, &swapchain->frontBuffer); if (FAILED(hr)) { WARN("Failed to create front buffer, hr %#x.\n", hr); goto err; } IWineD3DSurface_SetContainer(swapchain->frontBuffer, (IWineD3DBase *)swapchain); ((IWineD3DSurfaceImpl *)swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN; if (surface_type == SURFACE_OPENGL) { IWineD3DSurface_ModifyLocation(swapchain->frontBuffer, SFLAG_INDRAWABLE, TRUE); } /* MSDN says we're only allowed a single fullscreen swapchain per device, * so we should really check to see if there is a fullscreen swapchain * already. Does a single head count as full screen? */ if (!present_parameters->Windowed) { WINED3DDISPLAYMODE mode; /* Change the display settings */ mode.Width = present_parameters->BackBufferWidth; mode.Height = present_parameters->BackBufferHeight; mode.Format = present_parameters->BackBufferFormat; mode.RefreshRate = present_parameters->FullScreen_RefreshRateInHz; hr = IWineD3DDevice_SetDisplayMode((IWineD3DDevice *)device, 0, &mode); if (FAILED(hr)) { WARN("Failed to set display mode, hr %#x.\n", hr); goto err; } displaymode_set = TRUE; } #ifndef VBOX_WITH_WDDM swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(swapchain->context)); if (!swapchain->context) { ERR("Failed to create the context array.\n"); hr = E_OUTOFMEMORY; goto err; } swapchain->num_contexts = 1; #endif if (surface_type == SURFACE_OPENGL) { #ifdef VBOX_WITH_WDDM struct wined3d_context * swapchainContext; #endif const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; /* In WGL both color, depth and stencil are features of a pixel format. In case of D3D they are separate. * You are able to add a depth + stencil surface at a later stage when you need it. * In order to support this properly in WineD3D we need the ability to recreate the opengl context and * drawable when this is required. This is very tricky as we need to reapply ALL opengl states for the new * context, need torecreate shaders, textures and other resources. * * The context manager already takes care of the state problem and for the other tasks code from Reset * can be used. These changes are way to risky during the 1.0 code freeze which is taking place right now. * Likely a lot of other new bugs will be exposed. For that reason request a depth stencil surface all the * time. It can cause a slight performance hit but fixes a lot of regressions. A fixme reminds of that this * issue needs to be fixed. */ if (!present_parameters->EnableAutoDepthStencil || swapchain->presentParms.AutoDepthStencilFormat != WINED3DFMT_D24_UNORM_S8_UINT) { FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n"); } swapchain->ds_format = getFormatDescEntry(WINED3DFMT_D24_UNORM_S8_UINT, gl_info); #ifdef VBOX_WITH_WDDM swapchainContext = context_find_create(device, swapchain, (IWineD3DSurfaceImpl *)swapchain->frontBuffer, swapchain->ds_format); if (!swapchainContext) #else swapchain->context[0] = context_create(swapchain, (IWineD3DSurfaceImpl *)swapchain->frontBuffer, swapchain->ds_format); if (!swapchain->context[0]) #endif { WARN("Failed to create context.\n"); hr = WINED3DERR_NOTAVAILABLE; goto err; } #ifdef VBOX_WITH_WDDM context_release(swapchainContext); #else context_release(swapchain->context[0]); #endif } else { #ifndef VBOX_WITH_WDDM swapchain->context[0] = NULL; #endif } if (swapchain->presentParms.BackBufferCount > 0) { swapchain->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->backBuffer) * swapchain->presentParms.BackBufferCount); if (!swapchain->backBuffer) { ERR("Failed to allocate backbuffer array memory.\n"); hr = E_OUTOFMEMORY; goto err; } for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i) { TRACE("Creating back buffer %u.\n", i); hr = IWineD3DDeviceParent_CreateRenderTarget(device->device_parent, parent, swapchain->presentParms.BackBufferWidth, swapchain->presentParms.BackBufferHeight, swapchain->presentParms.BackBufferFormat, swapchain->presentParms.MultiSampleType, swapchain->presentParms.MultiSampleQuality, TRUE /* Lockable */, &swapchain->backBuffer[i]); if (FAILED(hr)) { WARN("Failed to create back buffer %u, hr %#x.\n", i, hr); goto err; } IWineD3DSurface_SetContainer(swapchain->backBuffer[i], (IWineD3DBase *)swapchain); ((IWineD3DSurfaceImpl *)swapchain->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN; } } /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */ if (present_parameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) { TRACE("Creating depth/stencil buffer.\n"); if (!device->auto_depth_stencil_buffer) { hr = IWineD3DDeviceParent_CreateDepthStencilSurface(device->device_parent, parent, swapchain->presentParms.BackBufferWidth, swapchain->presentParms.BackBufferHeight, swapchain->presentParms.AutoDepthStencilFormat, swapchain->presentParms.MultiSampleType, swapchain->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */, &device->auto_depth_stencil_buffer); if (FAILED(hr)) { WARN("Failed to create the auto depth stencil, hr %#x.\n", hr); goto err; } IWineD3DSurface_SetContainer(device->auto_depth_stencil_buffer, NULL); } } IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *)swapchain, &swapchain->orig_gamma); #ifdef VBOX_WITH_WDDM if (overridenSwapchain) { swapchain_invalidate(overridenSwapchain); } #endif return WINED3D_OK; err: if (displaymode_set) { DEVMODEW devmode; ClipCursor(NULL); /* Change the display settings */ memset(&devmode, 0, sizeof(devmode)); devmode.dmSize = sizeof(devmode); devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; devmode.dmBitsPerPel = format_desc->byte_count * 8; devmode.dmPelsWidth = swapchain->orig_width; devmode.dmPelsHeight = swapchain->orig_height; ChangeDisplaySettingsExW(adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL); } if (swapchain->backBuffer) { for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i) { if (swapchain->backBuffer[i]) IWineD3DSurface_Release(swapchain->backBuffer[i]); } HeapFree(GetProcessHeap(), 0, swapchain->backBuffer); } #ifdef VBOX_WITH_WDDM if (!device->NumberOfSwapChains) { while (device->numContexts) { context_destroy(device, device->contexts[0]); } } #else if (swapchain->context) { if (swapchain->context[0]) { context_release(swapchain->context[0]); context_destroy(device, swapchain->context[0]); swapchain->num_contexts = 0; } HeapFree(GetProcessHeap(), 0, swapchain->context); } #endif if (swapchain->frontBuffer) IWineD3DSurface_Release(swapchain->frontBuffer); #ifdef VBOX_WITH_WDDM if (!overridenSwapchain && swapchain->win_handle) { VBoxExtWndDestroy(swapchain->win_handle, swapchain->hDC); } swapchain_invalidate(swapchain); #endif return hr; }
static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) { IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; struct wined3d_context *context; RECT src_rect, dst_rect; BOOL render_to_fbo; unsigned int sync; int retval; #ifdef VBOX_WITH_WDDM /* quickly sort out invalid swapchains */ if (!This->hDC) { WARN("Invalid swapchain"); return WINED3D_OK; } #endif IWineD3DSwapChain_SetDestWindowOverride(iface, hDestWindowOverride); context = context_acquire(This->device, This->backBuffer[0], CTXUSAGE_RESOURCELOAD); if (!context->valid) { context_release(context); WARN("Invalid context, skipping present.\n"); return WINED3D_OK; } /* Render the cursor onto the back buffer, using our nifty directdraw blitting code :-) */ if (This->device->bCursorVisible && This->device->cursorTexture) { IWineD3DSurfaceImpl cursor; RECT destRect = { This->device->xScreenSpace - This->device->xHotSpot, This->device->yScreenSpace - This->device->yHotSpot, This->device->xScreenSpace + This->device->cursorWidth - This->device->xHotSpot, This->device->yScreenSpace + This->device->cursorHeight - This->device->yHotSpot, }; TRACE("Rendering the cursor. Creating fake surface at %p\n", &cursor); /* Build a fake surface to call the Blitting code. It is not possible to use the interface passed by * the application because we are only supposed to copy the information out. Using a fake surface * allows to use the Blitting engine and avoid copying the whole texture -> render target blitting code. */ memset(&cursor, 0, sizeof(cursor)); cursor.lpVtbl = &IWineD3DSurface_Vtbl; cursor.resource.ref = 1; cursor.resource.device = This->device; cursor.resource.pool = WINED3DPOOL_SCRATCH; cursor.resource.format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, context->gl_info); cursor.resource.resourceType = WINED3DRTYPE_SURFACE; cursor.texture_name = This->device->cursorTexture; cursor.texture_target = GL_TEXTURE_2D; cursor.texture_level = 0; cursor.currentDesc.Width = This->device->cursorWidth; cursor.currentDesc.Height = This->device->cursorHeight; /* The cursor must have pow2 sizes */ cursor.pow2Width = cursor.currentDesc.Width; cursor.pow2Height = cursor.currentDesc.Height; /* The surface is in the texture */ cursor.Flags |= SFLAG_INTEXTURE; /* DDBLT_KEYSRC will cause BltOverride to enable the alpha test with GL_NOTEQUAL, 0.0, * which is exactly what we want :-) */ if (This->presentParms.Windowed) { #ifdef VBOX_WITH_WDDM /* @todo: can we actualy be here? */ #endif MapWindowPoints(NULL, This->win_handle, (LPPOINT)&destRect, 2); } IWineD3DSurface_Blt(This->backBuffer[0], &destRect, (IWineD3DSurface *)&cursor, NULL, WINEDDBLT_KEYSRC, NULL, WINED3DTEXF_POINT); } if (This->device->logo_surface) { /* Blit the logo into the upper left corner of the drawable. */ IWineD3DSurface_BltFast(This->backBuffer[0], 0, 0, This->device->logo_surface, NULL, WINEDDBLTFAST_SRCCOLORKEY); } #ifdef VBOX_WITH_WDDM TRACE("Presenting HDC %p.\n", context->currentSwapchain->hDC); #else TRACE("Presenting HDC %p.\n", context->hdc); #endif render_to_fbo = This->render_to_fbo; if (pSourceRect) { src_rect = *pSourceRect; if (!render_to_fbo && (src_rect.left || src_rect.top || src_rect.right != This->presentParms.BackBufferWidth || src_rect.bottom != This->presentParms.BackBufferHeight)) { render_to_fbo = TRUE; } } else { src_rect.left = 0; src_rect.top = 0; src_rect.right = This->presentParms.BackBufferWidth; src_rect.bottom = This->presentParms.BackBufferHeight; } if (pDestRect) dst_rect = *pDestRect; #ifndef VBOX_WITH_WDDM else GetClientRect(This->win_handle, &dst_rect); if (!render_to_fbo && (dst_rect.left || dst_rect.top || dst_rect.right != This->presentParms.BackBufferWidth || dst_rect.bottom != This->presentParms.BackBufferHeight)) { render_to_fbo = TRUE; } #else else { dst_rect.left = 0; dst_rect.top = 0; dst_rect.right = This->presentParms.BackBufferWidth; dst_rect.bottom = This->presentParms.BackBufferHeight; } #endif /* Rendering to a window of different size, presenting partial rectangles, * or rendering to a different window needs help from FBO_blit or a textured * draw. Render the swapchain to a FBO in the future. * * Note that FBO_blit from the backbuffer to the frontbuffer cannot solve * all these issues - this fails if the window is smaller than the backbuffer. */ if (!This->render_to_fbo && render_to_fbo && wined3d_settings.offscreen_rendering_mode == ORM_FBO) { IWineD3DSurface_LoadLocation(This->backBuffer[0], SFLAG_INTEXTURE, NULL); IWineD3DSurface_ModifyLocation(This->backBuffer[0], SFLAG_INDRAWABLE, FALSE); This->render_to_fbo = TRUE; /* Force the context manager to update the render target configuration next draw. */ context->current_rt = NULL; } if(This->render_to_fbo) { /* This codepath should only be hit with the COPY swapeffect. Otherwise a backbuffer- * window size mismatch is impossible(fullscreen) and src and dst rectangles are * not allowed(they need the COPY swapeffect) * * The DISCARD swap effect is ok as well since any backbuffer content is allowed after * the swap */ if(This->presentParms.SwapEffect == WINED3DSWAPEFFECT_FLIP ) { FIXME("Render-to-fbo with WINED3DSWAPEFFECT_FLIP\n"); } swapchain_blit(This, context, &src_rect, &dst_rect); } #ifdef VBOX_WITH_WDDM if (This->device->numContexts > 1) wglFinish(); #else if (This->num_contexts > 1) wglFinish(); #endif #if defined(VBOX_WITH_WDDM) && defined(DEBUG) { HWND wnd = WindowFromDC(context->currentSwapchain->hDC); Assert(wnd == context->currentSwapchain->win_handle); } #endif #ifdef VBOX_WITH_WDDM /* We're directly using wglMakeCurrent calls skipping GDI layer, which causes GDI SwapBuffers to fail trying to * call glFinish, which doesn't have any context set. So we use wglSwapLayerBuffers directly as well. */ pwglSwapLayerBuffers(context->currentSwapchain->hDC, WGL_SWAP_MAIN_PLANE); #else # ifdef VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT pwglSwapLayerBuffers(context->hdc, WGL_SWAP_MAIN_PLANE); # else SwapBuffers(context->hdc); /* TODO: cycle through the swapchain buffers */ # endif #endif TRACE("SwapBuffers called, Starting new frame\n"); /* FPS support */ if (TRACE_ON(fps)) { DWORD time = GetTickCount(); This->frames++; /* every 1.5 seconds */ if (time - This->prev_time > 1500) { TRACE_(fps)("%p @ approx %.2ffps\n", This, 1000.0*This->frames/(time - This->prev_time)); This->prev_time = time; This->frames = 0; } } #if defined(FRAME_DEBUGGING) { if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) { if (!isOn) { isOn = TRUE; FIXME("Enabling D3D Trace\n"); __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 1); #if defined(SHOW_FRAME_MAKEUP) FIXME("Singe Frame snapshots Starting\n"); isDumpingFrames = TRUE; ENTER_GL(); glClear(GL_COLOR_BUFFER_BIT); LEAVE_GL(); #endif #if defined(SINGLE_FRAME_DEBUGGING) } else { #if defined(SHOW_FRAME_MAKEUP) FIXME("Singe Frame snapshots Finishing\n"); isDumpingFrames = FALSE; #endif FIXME("Singe Frame trace complete\n"); DeleteFileA("C:\\D3DTRACE"); __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0); #endif } } else { if (isOn) { isOn = FALSE; #if defined(SHOW_FRAME_MAKEUP) FIXME("Single Frame snapshots Finishing\n"); isDumpingFrames = FALSE; #endif FIXME("Disabling D3D Trace\n"); __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0); } } } #endif /* This is disabled, but the code left in for debug purposes. * * Since we're allowed to modify the new back buffer on a D3DSWAPEFFECT_DISCARD flip, * we can clear it with some ugly color to make bad drawing visible and ease debugging. * The Debug runtime does the same on Windows. However, a few games do not redraw the * screen properly, like Max Payne 2, which leaves a few pixels undefined. * * Tests show that the content of the back buffer after a discard flip is indeed not * reliable, so no game can depend on the exact content. However, it resembles the * old contents in some way, for example by showing fragments at other locations. In * general, the color theme is still intact. So Max payne, which draws rather dark scenes * gets a dark background image. If we clear it with a bright ugly color, the game's * bug shows up much more than it does on Windows, and the players see single pixels * with wrong colors. * (The Max Payne bug has been confirmed on Windows with the debug runtime) */ if (FALSE && This->presentParms.SwapEffect == WINED3DSWAPEFFECT_DISCARD) { TRACE("Clearing the color buffer with cyan color\n"); IWineD3DDevice_Clear((IWineD3DDevice *)This->device, 0, NULL, WINED3DCLEAR_TARGET, 0xff00ffff, 1.0f, 0); } if(!This->render_to_fbo && ( ((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags & SFLAG_INSYSMEM || ((IWineD3DSurfaceImpl *) This->backBuffer[0])->Flags & SFLAG_INSYSMEM ) ) { /* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying * Doesn't work with render_to_fbo because we're not flipping */ IWineD3DSurfaceImpl *front = (IWineD3DSurfaceImpl *) This->frontBuffer; IWineD3DSurfaceImpl *back = (IWineD3DSurfaceImpl *) This->backBuffer[0]; if(front->resource.size == back->resource.size) { DWORD fbflags; flip_surface(front, back); /* Tell the front buffer surface that is has been modified. However, * the other locations were preserved during that, so keep the flags. * This serves to update the emulated overlay, if any */ fbflags = front->Flags; IWineD3DSurface_ModifyLocation(This->frontBuffer, SFLAG_INDRAWABLE, TRUE); front->Flags = fbflags; } else { IWineD3DSurface_ModifyLocation((IWineD3DSurface *) front, SFLAG_INDRAWABLE, TRUE); IWineD3DSurface_ModifyLocation((IWineD3DSurface *) back, SFLAG_INDRAWABLE, TRUE); } } else { IWineD3DSurface_ModifyLocation(This->frontBuffer, SFLAG_INDRAWABLE, TRUE); /* If the swapeffect is DISCARD, the back buffer is undefined. That means the SYSMEM * and INTEXTURE copies can keep their old content if they have any defined content. * If the swapeffect is COPY, the content remains the same. If it is FLIP however, * the texture / sysmem copy needs to be reloaded from the drawable */ if(This->presentParms.SwapEffect == WINED3DSWAPEFFECT_FLIP) { IWineD3DSurface_ModifyLocation(This->backBuffer[0], SFLAG_INDRAWABLE, TRUE); } } if (This->device->stencilBufferTarget) { if (This->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL || ((IWineD3DSurfaceImpl *)This->device->stencilBufferTarget)->Flags & SFLAG_DISCARD) { surface_modify_ds_location(This->device->stencilBufferTarget, SFLAG_DS_DISCARDED); } } if (This->presentParms.PresentationInterval != WINED3DPRESENT_INTERVAL_IMMEDIATE && context->gl_info->supported[SGI_VIDEO_SYNC]) { retval = GL_EXTCALL(glXGetVideoSyncSGI(&sync)); if(retval != 0) { ERR("glXGetVideoSyncSGI failed(retval = %d\n", retval); } switch(This->presentParms.PresentationInterval) { case WINED3DPRESENT_INTERVAL_DEFAULT: case WINED3DPRESENT_INTERVAL_ONE: if(sync <= This->vSyncCounter) { retval = GL_EXTCALL(glXWaitVideoSyncSGI(1, 0, &This->vSyncCounter)); } else { This->vSyncCounter = sync; } break; case WINED3DPRESENT_INTERVAL_TWO: if(sync <= This->vSyncCounter + 1) { retval = GL_EXTCALL(glXWaitVideoSyncSGI(2, This->vSyncCounter & 0x1, &This->vSyncCounter)); } else { This->vSyncCounter = sync; } break; case WINED3DPRESENT_INTERVAL_THREE: if(sync <= This->vSyncCounter + 2) { retval = GL_EXTCALL(glXWaitVideoSyncSGI(3, This->vSyncCounter % 0x3, &This->vSyncCounter)); } else { This->vSyncCounter = sync; } break; case WINED3DPRESENT_INTERVAL_FOUR: if(sync <= This->vSyncCounter + 3) { retval = GL_EXTCALL(glXWaitVideoSyncSGI(4, This->vSyncCounter & 0x3, &This->vSyncCounter)); } else { This->vSyncCounter = sync; } break; default: FIXME("Unknown presentation interval %08x\n", This->presentParms.PresentationInterval); } } context_release(context); TRACE("returning\n"); return WINED3D_OK; }
HRESULT vertexdeclaration_init(IWineD3DVertexDeclarationImpl *declaration, IWineD3DDeviceImpl *device, const WINED3DVERTEXELEMENT *elements, UINT element_count, IUnknown *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; WORD preloaded = 0; /* MAX_STREAMS, 16 */ unsigned int i; if (TRACE_ON(d3d_decl)) { for (i = 0; i < element_count; ++i) { dump_wined3dvertexelement(elements + i); } } declaration->lpVtbl = &IWineD3DVertexDeclaration_Vtbl; declaration->ref = 1; declaration->parent = parent; declaration->parent_ops = parent_ops; declaration->device = device; declaration->elements = HeapAlloc(GetProcessHeap(), 0, sizeof(*declaration->elements) * element_count); if (!declaration->elements) { ERR("Failed to allocate elements memory.\n"); return E_OUTOFMEMORY; } declaration->element_count = element_count; /* Do some static analysis on the elements to make reading the * declaration more comfortable for the drawing code. */ for (i = 0; i < element_count; ++i) { struct wined3d_vertex_declaration_element *e = &declaration->elements[i]; e->format_desc = getFormatDescEntry(elements[i].format, gl_info); e->ffp_valid = declaration_element_valid_ffp(&elements[i]); e->input_slot = elements[i].input_slot; e->offset = elements[i].offset; e->output_slot = elements[i].output_slot; e->method = elements[i].method; e->usage = elements[i].usage; e->usage_idx = elements[i].usage_idx; if (e->usage == WINED3DDECLUSAGE_POSITIONT) declaration->position_transformed = TRUE; /* Find the streams used in the declaration. The vertex buffers have * to be loaded when drawing, but filter tesselation pseudo streams. */ if (e->input_slot >= MAX_STREAMS) continue; if (!e->format_desc->gl_vtx_format) { FIXME("The application tries to use an unsupported format (%s), returning E_FAIL.\n", debug_d3dformat(elements[i].format)); HeapFree(GetProcessHeap(), 0, declaration->elements); return E_FAIL; } if (e->offset & 0x3) { WARN("Declaration element %u is not 4 byte aligned(%u), returning E_FAIL.\n", i, e->offset); HeapFree(GetProcessHeap(), 0, declaration->elements); return E_FAIL; } if (!(preloaded & (1 << e->input_slot))) { declaration->streams[declaration->num_streams] = e->input_slot; ++declaration->num_streams; preloaded |= 1 << e->input_slot; } if (elements[i].format == WINED3DFMT_R16G16_FLOAT || elements[i].format == WINED3DFMT_R16G16B16A16_FLOAT) { if (!gl_info->supported[ARB_HALF_FLOAT_VERTEX]) declaration->half_float_conv_needed = TRUE; } } return WINED3D_OK; }
HRESULT texture_init(IWineD3DTextureImpl *texture, UINT width, UINT height, UINT levels, IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format, WINED3DPOOL pool, IUnknown *parent, const struct wined3d_parent_ops *parent_ops #ifdef VBOX_WITH_WDDM , HANDLE *shared_handle , void **pavClientMem #endif ) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, gl_info); UINT pow2_width, pow2_height; UINT tmp_w, tmp_h; unsigned int i; HRESULT hr; /* TODO: It should only be possible to create textures for formats * that are reported as supported. */ if (WINED3DFMT_UNKNOWN >= format) { WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture); return WINED3DERR_INVALIDCALL; } /* Non-power2 support. */ if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO]) { pow2_width = width; pow2_height = height; } else { /* Find the nearest pow2 match. */ pow2_width = pow2_height = 1; while (pow2_width < width) pow2_width <<= 1; while (pow2_height < height) pow2_height <<= 1; if (pow2_width != width || pow2_height != height) { if (levels > 1) { WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } } /* Calculate levels for mip mapping. */ if (usage & WINED3DUSAGE_AUTOGENMIPMAP) { if (!gl_info->supported[SGIS_GENERATE_MIPMAP]) { WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } if (levels > 1) { WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning WINED3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } else if (!levels) { levels = wined3d_log2i(max(width, height)) + 1; TRACE("Calculated levels = %u.\n", levels); } texture->lpVtbl = &IWineD3DTexture_Vtbl; hr = basetexture_init((IWineD3DBaseTextureImpl *)texture, levels, WINED3DRTYPE_TEXTURE, device, 0, usage, format_desc, pool, parent, parent_ops #ifdef VBOX_WITH_WDDM , shared_handle, pavClientMem #endif ); if (FAILED(hr)) { WARN("Failed to initialize basetexture, returning %#x.\n", hr); return hr; } /* Precalculated scaling for 'faked' non power of two texture coords. * Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE * is used in combination with texture uploads (RTL_READTEX). The reason is that EXT_PALETTED_TEXTURE * doesn't work in combination with ARB_TEXTURE_RECTANGLE. */ if (gl_info->supported[WINE_NORMALIZED_TEXRECT] && (width != pow2_width || height != pow2_height)) { texture->baseTexture.pow2Matrix[0] = 1.0f; texture->baseTexture.pow2Matrix[5] = 1.0f; texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_2D; texture->cond_np2 = TRUE; texture->baseTexture.minMipLookup = minMipLookup_noFilter; } else if (gl_info->supported[ARB_TEXTURE_RECTANGLE] && (width != pow2_width || height != pow2_height) && !(format_desc->format == WINED3DFMT_P8_UINT && gl_info->supported[EXT_PALETTED_TEXTURE] && wined3d_settings.rendertargetlock_mode == RTL_READTEX)) { if ((width != 1) || (height != 1)) texture->baseTexture.pow2Matrix_identity = FALSE; texture->baseTexture.pow2Matrix[0] = (float)width; texture->baseTexture.pow2Matrix[5] = (float)height; texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_RECTANGLE_ARB; texture->cond_np2 = TRUE; if(texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) { texture->baseTexture.minMipLookup = minMipLookup_noMip; } else { texture->baseTexture.minMipLookup = minMipLookup_noFilter; } } else { if ((width != pow2_width) || (height != pow2_height)) { texture->baseTexture.pow2Matrix_identity = FALSE; texture->baseTexture.pow2Matrix[0] = (((float)width) / ((float)pow2_width)); texture->baseTexture.pow2Matrix[5] = (((float)height) / ((float)pow2_height)); } else { texture->baseTexture.pow2Matrix[0] = 1.0f; texture->baseTexture.pow2Matrix[5] = 1.0f; } texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_2D; texture->cond_np2 = FALSE; } TRACE("xf(%f) yf(%f)\n", texture->baseTexture.pow2Matrix[0], texture->baseTexture.pow2Matrix[5]); /* Generate all the surfaces. */ tmp_w = width; tmp_h = height; for (i = 0; i < texture->baseTexture.levels; ++i) { #ifdef VBOX_WITH_WDDM /* Use the callback to create the texture surface. */ hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format, usage, pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &texture->surfaces[i] , NULL /* <- we first create a surface in an everage "non-shared" fashion and initialize its share properties later (see below) * this is done this way because the surface does not have its parent (texture) setup properly * thus we can not initialize texture at this stage */ , pavClientMem ? pavClientMem[i] : NULL); #else /* Use the callback to create the texture surface. */ hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format, usage, pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &texture->surfaces[i]); #endif if (FAILED(hr)) { FIXME("Failed to create surface %p, hr %#x\n", texture, hr); texture->surfaces[i] = NULL; texture_cleanup(texture); return hr; } IWineD3DSurface_SetContainer(texture->surfaces[i], (IWineD3DBase *)texture); TRACE("Created surface level %u @ %p.\n", i, texture->surfaces[i]); surface_set_texture_target(texture->surfaces[i], texture->target); /* Calculate the next mipmap level. */ tmp_w = max(1, tmp_w >> 1); tmp_h = max(1, tmp_h >> 1); } texture->baseTexture.internal_preload = texture_internal_preload; #ifdef VBOX_WITH_WDDM if (VBOXSHRC_IS_SHARED(texture)) { Assert(shared_handle); for (i = 0; i < texture->baseTexture.levels; ++i) { VBOXSHRC_COPY_SHAREDATA((IWineD3DSurfaceImpl*)texture->surfaces[i], texture); } #ifdef DEBUG for (i = 0; i < texture->baseTexture.levels; ++i) { Assert(!((IWineD3DSurfaceImpl*)texture->surfaces[i])->texture_name); } #endif for (i = 0; i < texture->baseTexture.levels; ++i) { if (!VBOXSHRC_IS_SHARED_OPENED(texture)) { IWineD3DSurface_LoadLocation(texture->surfaces[i], SFLAG_INTEXTURE, NULL); Assert(!(*shared_handle)); *shared_handle = VBOXSHRC_GET_SHAREHANDLE(texture); } else { surface_setup_location_onopen((IWineD3DSurfaceImpl*)texture->surfaces[i]); Assert(*shared_handle); Assert(*shared_handle == VBOXSHRC_GET_SHAREHANDLE(texture)); } } #ifdef DEBUG for (i = 0; i < texture->baseTexture.levels; ++i) { Assert((GLuint)(*shared_handle) == ((IWineD3DSurfaceImpl*)texture->surfaces[i])->texture_name); } #endif if (!VBOXSHRC_IS_SHARED_OPENED(texture)) { struct wined3d_context * context; Assert(!device->isInDraw); /* flush to ensure the texture is allocated before it is used by another * process opening it */ context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD); if (context->valid) { wglFlush(); } else { ERR("invalid context!"); } context_release(context); } } else { Assert(!shared_handle); } #endif return WINED3D_OK; }
HRESULT texture_init(IWineD3DTextureImpl *texture, UINT width, UINT height, UINT levels, IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format, WINED3DPOOL pool, IUnknown *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, gl_info); UINT pow2_width, pow2_height; UINT tmp_w, tmp_h; unsigned int i; HRESULT hr; /* TODO: It should only be possible to create textures for formats * that are reported as supported. */ if (WINED3DFMT_UNKNOWN >= format) { WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture); return WINED3DERR_INVALIDCALL; } /* Non-power2 support. */ if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO]) { pow2_width = width; pow2_height = height; } else { /* Find the nearest pow2 match. */ pow2_width = pow2_height = 1; while (pow2_width < width) pow2_width <<= 1; while (pow2_height < height) pow2_height <<= 1; if (pow2_width != width || pow2_height != height) { if (levels > 1) { WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } } /* Calculate levels for mip mapping. */ if (usage & WINED3DUSAGE_AUTOGENMIPMAP) { if (!gl_info->supported[SGIS_GENERATE_MIPMAP]) { WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } if (levels > 1) { WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning WINED3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } else if (!levels) { levels = wined3d_log2i(max(width, height)) + 1; TRACE("Calculated levels = %u.\n", levels); } texture->lpVtbl = &IWineD3DTexture_Vtbl; hr = basetexture_init((IWineD3DBaseTextureImpl *)texture, 1, levels, WINED3DRTYPE_TEXTURE, device, 0, usage, format_desc, pool, parent, parent_ops); if (FAILED(hr)) { WARN("Failed to initialize basetexture, returning %#x.\n", hr); return hr; } /* Precalculated scaling for 'faked' non power of two texture coords. * Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE * is used in combination with texture uploads (RTL_READTEX). The reason is that EXT_PALETTED_TEXTURE * doesn't work in combination with ARB_TEXTURE_RECTANGLE. */ if (gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT] && (width != pow2_width || height != pow2_height)) { texture->baseTexture.pow2Matrix[0] = 1.0f; texture->baseTexture.pow2Matrix[5] = 1.0f; texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_2D; texture->cond_np2 = TRUE; texture->baseTexture.minMipLookup = minMipLookup_noFilter; } else if (gl_info->supported[ARB_TEXTURE_RECTANGLE] && (width != pow2_width || height != pow2_height) && !(format_desc->format == WINED3DFMT_P8_UINT && gl_info->supported[EXT_PALETTED_TEXTURE] && wined3d_settings.rendertargetlock_mode == RTL_READTEX)) { if ((width != 1) || (height != 1)) texture->baseTexture.pow2Matrix_identity = FALSE; texture->baseTexture.pow2Matrix[0] = (float)width; texture->baseTexture.pow2Matrix[5] = (float)height; texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_RECTANGLE_ARB; texture->cond_np2 = TRUE; if(texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) { texture->baseTexture.minMipLookup = minMipLookup_noMip; } else { texture->baseTexture.minMipLookup = minMipLookup_noFilter; } } else { if ((width != pow2_width) || (height != pow2_height)) { texture->baseTexture.pow2Matrix_identity = FALSE; texture->baseTexture.pow2Matrix[0] = (((float)width) / ((float)pow2_width)); texture->baseTexture.pow2Matrix[5] = (((float)height) / ((float)pow2_height)); } else { texture->baseTexture.pow2Matrix[0] = 1.0f; texture->baseTexture.pow2Matrix[5] = 1.0f; } texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_2D; texture->cond_np2 = FALSE; } TRACE("xf(%f) yf(%f)\n", texture->baseTexture.pow2Matrix[0], texture->baseTexture.pow2Matrix[5]); /* Generate all the surfaces. */ tmp_w = width; tmp_h = height; for (i = 0; i < texture->baseTexture.level_count; ++i) { IWineD3DSurface *surface; /* Use the callback to create the texture surface. */ hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format, usage, pool, i, 0, &surface); if (FAILED(hr)) { FIXME("Failed to create surface %p, hr %#x\n", texture, hr); texture_cleanup(texture); return hr; } IWineD3DSurface_SetContainer(surface, (IWineD3DBase *)texture); surface_set_texture_target((IWineD3DSurfaceImpl *)surface, texture->target); texture->baseTexture.sub_resources[i] = (IWineD3DResourceImpl *)surface; TRACE("Created surface level %u @ %p.\n", i, surface); /* Calculate the next mipmap level. */ tmp_w = max(1, tmp_w >> 1); tmp_h = max(1, tmp_h >> 1); } texture->baseTexture.internal_preload = texture_internal_preload; return WINED3D_OK; }