/* Routine common to the draw primitive and draw indexed primitive routines */ void drawPrimitive(IWineD3DDeviceImpl *device, UINT index_count, UINT StartIdx, UINT idxSize, const void *idxData) { const struct wined3d_state *state = &device->stateBlock->state; struct wined3d_context *context; unsigned int i; if (!index_count) return; if (state->render_states[WINED3DRS_COLORWRITEENABLE]) { /* Invalidate the back buffer memory so LockRect will read it the next time */ for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i) { IWineD3DSurfaceImpl *target = device->render_targets[i]; if (target) { surface_load_location(target, SFLAG_INDRAWABLE, NULL); surface_modify_location(target, SFLAG_INDRAWABLE, TRUE); } } } /* Signals other modules that a drawing is in progress and the stateblock finalized */ device->isInDraw = TRUE; context = context_acquire(device, device->render_targets[0]); if (!context->valid) { context_release(context); WARN("Invalid context, skipping draw.\n"); return; } context_apply_draw_state(context, device); if (device->depth_stencil) { /* Note that this depends on the context_acquire() call above to set * context->render_offscreen properly. We don't currently take the * Z-compare function into account, but we could skip loading the * depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well. Also note * that we never copy the stencil data.*/ DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN; if (state->render_states[WINED3DRS_ZWRITEENABLE] || state->render_states[WINED3DRS_ZENABLE]) { IWineD3DSurfaceImpl *ds = device->depth_stencil; RECT current_rect, draw_rect, r; if (location == SFLAG_DS_ONSCREEN && ds != device->onscreen_depth_stencil) device_switch_onscreen_ds(device, context, ds); if (ds->flags & location) SetRect(¤t_rect, 0, 0, ds->ds_current_size.cx, ds->ds_current_size.cy); else SetRectEmpty(¤t_rect); device_get_draw_rect(device, &draw_rect); IntersectRect(&r, &draw_rect, ¤t_rect); if (!EqualRect(&r, &draw_rect)) surface_load_ds_location(ds, context, location); if (state->render_states[WINED3DRS_ZWRITEENABLE]) { surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy); surface_modify_location(ds, SFLAG_INDRAWABLE, TRUE); } } } if ((!context->gl_info->supported[WINED3D_GL_VERSION_2_0] || (!glPointParameteri && !context->gl_info->supported[NV_POINT_SPRITE])) && context->render_offscreen && state->render_states[WINED3DRS_POINTSPRITEENABLE] && state->gl_primitive_type == GL_POINTS) { FIXME("Point sprite coordinate origin switching not supported.\n"); } /* Ok, we will be updating the screen from here onwards so grab the lock */ ENTER_GL(); { GLenum glPrimType = state->gl_primitive_type; BOOL emulation = FALSE; const struct wined3d_stream_info *stream_info = &device->strided_streams; struct wined3d_stream_info stridedlcl; if (!use_vs(state)) { if (!stream_info->position_transformed && context->num_untracked_materials && state->render_states[WINED3DRS_LIGHTING]) { static BOOL warned; if (!warned) { FIXME("Using software emulation because not all material properties could be tracked\n"); warned = TRUE; } else { TRACE("Using software emulation because not all material properties could be tracked\n"); } emulation = TRUE; } else if (context->fog_coord && state->render_states[WINED3DRS_FOGENABLE]) { /* Either write a pipeline replacement shader or convert the specular alpha from unsigned byte * to a float in the vertex buffer */ static BOOL warned; if (!warned) { FIXME("Using software emulation because manual fog coordinates are provided\n"); warned = TRUE; } else { TRACE("Using software emulation because manual fog coordinates are provided\n"); } emulation = TRUE; } if(emulation) { stream_info = &stridedlcl; memcpy(&stridedlcl, &device->strided_streams, sizeof(stridedlcl)); remove_vbos(context->gl_info, state, &stridedlcl); } } if (device->useDrawStridedSlow || emulation) { /* Immediate mode drawing */ if (use_vs(state)) { static BOOL warned; if (!warned) { FIXME("Using immediate mode with vertex shaders for half float emulation\n"); warned = TRUE; } else { TRACE("Using immediate mode with vertex shaders for half float emulation\n"); } drawStridedSlowVs(context->gl_info, state, stream_info, index_count, glPrimType, idxData, idxSize, StartIdx); } else { drawStridedSlow(device, context, stream_info, index_count, glPrimType, idxData, idxSize, StartIdx); } } else if (device->instancedDraw) { /* Instancing emulation with mixing immediate mode and arrays */ drawStridedInstanced(context->gl_info, state, stream_info, index_count, glPrimType, idxData, idxSize, StartIdx); } else { drawStridedFast(glPrimType, index_count, idxSize, idxData, StartIdx); } } /* Finished updating the screen, restore lock */ LEAVE_GL(); for(i = 0; i < device->num_buffer_queries; ++i) { wined3d_event_query_issue(device->buffer_queries[i], device); } if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ context_release(context); TRACE("Done all gl drawing\n"); /* Control goes back to the device, stateblock values may change again */ device->isInDraw = FALSE; }
/* Routine common to the draw primitive and draw indexed primitive routines */ void drawPrimitive(IWineD3DDevice *iface, UINT index_count, UINT StartIdx, UINT idxSize, const void *idxData) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; IWineD3DSurfaceImpl *target; struct wined3d_context *context; unsigned int i; if (!index_count) return; if (This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE]) { /* Invalidate the back buffer memory so LockRect will read it the next time */ for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i) { target = (IWineD3DSurfaceImpl *)This->render_targets[i]; if (target) { IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL); IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE); } } } /* Signals other modules that a drawing is in progress and the stateblock finalized */ This->isInDraw = TRUE; context = context_acquire(This, This->render_targets[0], CTXUSAGE_DRAWPRIM); if (!context->valid) { context_release(context); WARN("Invalid context, skipping draw.\n"); return; } #if defined(VBOX_WITH_WDDM) DBGL_CHECK_DRAWPRIM(context->gl_info, This); #endif if (This->stencilBufferTarget) { /* Note that this depends on the context_acquire() call above to set * This->render_offscreen properly. We don't currently take the * Z-compare function into account, but we could skip loading the * depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well. Also note * that we never copy the stencil data.*/ DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN; if (This->stateBlock->renderState[WINED3DRS_ZWRITEENABLE] || This->stateBlock->renderState[WINED3DRS_ZENABLE]) surface_load_ds_location(This->stencilBufferTarget, context, location); if (This->stateBlock->renderState[WINED3DRS_ZWRITEENABLE]) surface_modify_ds_location(This->stencilBufferTarget, location); } /* Ok, we will be updating the screen from here onwards so grab the lock */ ENTER_GL(); { GLenum glPrimType = This->stateBlock->gl_primitive_type; BOOL emulation = FALSE; const struct wined3d_stream_info *stream_info = &This->strided_streams; struct wined3d_stream_info stridedlcl; if (!use_vs(This->stateBlock)) { if (!This->strided_streams.position_transformed && context->num_untracked_materials && This->stateBlock->renderState[WINED3DRS_LIGHTING]) { static BOOL warned; if (!warned) { FIXME("Using software emulation because not all material properties could be tracked\n"); warned = TRUE; } else { TRACE("Using software emulation because not all material properties could be tracked\n"); } emulation = TRUE; } else if (context->fog_coord && This->stateBlock->renderState[WINED3DRS_FOGENABLE]) { /* Either write a pipeline replacement shader or convert the specular alpha from unsigned byte * to a float in the vertex buffer */ static BOOL warned; if (!warned) { FIXME("Using software emulation because manual fog coordinates are provided\n"); warned = TRUE; } else { TRACE("Using software emulation because manual fog coordinates are provided\n"); } emulation = TRUE; } if(emulation) { stream_info = &stridedlcl; memcpy(&stridedlcl, &This->strided_streams, sizeof(stridedlcl)); remove_vbos(This, &stridedlcl); } } if (This->useDrawStridedSlow || emulation) { /* Immediate mode drawing */ if (use_vs(This->stateBlock)) { static BOOL warned; if (!warned) { FIXME("Using immediate mode with vertex shaders for half float emulation\n"); warned = TRUE; } else { TRACE("Using immediate mode with vertex shaders for half float emulation\n"); } drawStridedSlowVs(iface, stream_info, index_count, glPrimType, idxData, idxSize, StartIdx); } else { drawStridedSlow(iface, context, stream_info, index_count, glPrimType, idxData, idxSize, StartIdx); } } else if(This->instancedDraw) { /* Instancing emulation with mixing immediate mode and arrays */ drawStridedInstanced(iface, &This->strided_streams, index_count, glPrimType, idxData, idxSize, StartIdx); } else { drawStridedFast(iface, glPrimType, index_count, idxSize, idxData, StartIdx); } } /* Finished updating the screen, restore lock */ LEAVE_GL(); for(i = 0; i < This->num_buffer_queries; i++) { wined3d_event_query_issue(This->buffer_queries[i], This); } if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ context_release(context); TRACE("Done all gl drawing\n"); /* Diagnostics */ #ifdef SHOW_FRAME_MAKEUP { static long int primCounter = 0; /* NOTE: set primCounter to the value reported by drawprim before you want to to write frame makeup to /tmp */ if (primCounter >= 0) { WINED3DLOCKED_RECT r; char buffer[80]; IWineD3DSurface_LockRect(This->render_targets[0], &r, NULL, WINED3DLOCK_READONLY); sprintf(buffer, "/tmp/backbuffer_%ld.tga", primCounter); TRACE("Saving screenshot %s\n", buffer); IWineD3DSurface_SaveSnapshot(This->render_targets[0], buffer); IWineD3DSurface_UnlockRect(This->render_targets[0]); #ifdef SHOW_TEXTURE_MAKEUP { IWineD3DSurface *pSur; int textureNo; for (textureNo = 0; textureNo < MAX_COMBINED_SAMPLERS; ++textureNo) { if (This->stateBlock->textures[textureNo] != NULL) { sprintf(buffer, "/tmp/texture_%p_%ld_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo); TRACE("Saving texture %s\n", buffer); if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) { IWineD3DTexture_GetSurfaceLevel(This->stateBlock->textures[textureNo], 0, &pSur); IWineD3DSurface_SaveSnapshot(pSur, buffer); IWineD3DSurface_Release(pSur); } else { FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo])); } } } } #endif } TRACE("drawprim #%ld\n", primCounter); ++primCounter; } #endif /* Control goes back to the device, stateblock values may change again */ This->isInDraw = FALSE; }
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; }