How to use DirectX3D render gtk window on window platform?
I use the following code, and when I click to trigger rendering, the window background does not change. The goal is that the window should turn black.
But after setting the environment variable GTK_CSD=0, the rendering is triggered, and the entire client area of the window becomes transparent.
I have also referred to d3dveosink in gstreamer, but encountered the same problem. When not set GTK_CSD=0, the window remains unchanged; Set GTK_CSD=0, image data can be displayed, but the image data is transparent.
I don't understand where the problem lies. Can someone who is good at it point it out?
I try use WIN32 API create window and export HWND the D3D render right. Replace WIN32 HWND to GTK window is not work.
#include <windows.h>
#include <tchar.h>
#include <windows.h>
#include <d3d9.h>
#include <dxva2api.h>
#include <initguid.h>
#include <gtk/gtk.h>
#include <gtk/gtk.h>
#include <dinput.h>
#include <ime.h>
#include <gdk/gdkwin32.h>
static void debug_info(const char* format, ...)
{
va_list args;
va_start(args, format);
char buffer[1024];
vsprintf(buffer, format, args);
FILE* fp = fopen("output.txt", "a+");
if (fp)
{
fprintf(fp, "%s", buffer);
fclose(fp);
}
va_end(args);
}
#define ERROR_CHECK_HR(hr) \
if (hr != S_OK) \
{ \
debug_info("%s:%d, hr=%u\n", __FUNCTION__, __LINE__, hr); \
}
typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT);
static IDirect3D9* g_d3d9;
IDirect3DDevice9* g_d3d_device = NULL;
IDirect3DSurface9* g_surface = NULL;
D3DTEXTUREFILTERTYPE filter_type;
gint sample_render(GtkWidget* widget, GdkEvent* event, gpointer data)
{
HRESULT hr;
IDirect3DSurface9* pBackBuffer = NULL;
D3DLOCKED_RECT LockedRect;
int lock_flags = 0;
/* copy data to surface */
hr = IDirect3DSurface9_LockRect(g_surface, &LockedRect, NULL, lock_flags);
/* copy argb data to LockedRect.pBits work */
uint8_t* dst = (uint8_t*)LockedRect.pBits;
int dst_stride = LockedRect.Pitch;
for (int i = 0; i < 900; i++)
{
memset(dst, 0, dst_stride);
dst += dst_stride;
}
IDirect3DSurface9_UnlockRect(g_surface);
RECT SourceRect = { 0, 0, 1440, 900 };
/* render */
hr = IDirect3DDevice9Ex_Clear(g_d3d_device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0),
1.0f, 0);
ERROR_CHECK_HR(hr);
hr = IDirect3DDevice9Ex_BeginScene(g_d3d_device);
ERROR_CHECK_HR(hr);
hr =
IDirect3DDevice9Ex_GetBackBuffer(g_d3d_device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
ERROR_CHECK_HR(hr);
hr = IDirect3DDevice9Ex_SetRenderTarget(g_d3d_device, 0, pBackBuffer);
ERROR_CHECK_HR(hr);
hr = IDirect3DDevice9Ex_StretchRect(g_d3d_device, g_surface, &SourceRect, pBackBuffer, NULL,
D3DTEXF_LINEAR); // D3DTEXF_LINEAR or D3DTEXF_POINT
ERROR_CHECK_HR(hr);
hr = IDirect3DDevice9Ex_EndScene(g_d3d_device);
ERROR_CHECK_HR(hr);
hr = IDirect3DDevice9Ex_Present(g_d3d_device, NULL, NULL, NULL, NULL);
ERROR_CHECK_HR(hr);
hr = IDirect3DSurface9_Release(pBackBuffer);
ERROR_CHECK_HR(hr);
debug_info("Direct3D present.\n");
return TRUE;
}
static gboolean draw_event(GtkWidget* widget, cairo_t* cr, gpointer data)
{
debug_info("draw_event\n");
/* ignore default draw work */
return TRUE;
}
static void drawing_area_realize(GtkWidget* area, gpointer user_data)
{
D3DPRESENT_PARAMETERS present_params = { 0 };
HWND hwnd;
GdkWindow* gdk_window;
HRESULT hr;
HMODULE d3dlib = LoadLibraryA("d3d9.dll");
pDirect3DCreate9* createD3D = (pDirect3DCreate9*)GetProcAddress(d3dlib, "Direct3DCreate9");
gdk_window = gtk_widget_get_window(area);
hwnd = GDK_WINDOW_HWND(gdk_window);
debug_info("drawing_area_realize HWND:0x%08lx for 0x%08lx", hwnd, area);
g_d3d9 = createD3D(D3D_SDK_VERSION);
if (!g_d3d9)
{
debug_info("Failed to create Direct3D9 object\n");
return;
}
DWORD create_mask = 0;
D3DCAPS9 caps;
D3DDISPLAYMODE disp_mode;
hr = IDirect3D9_GetAdapterDisplayMode(g_d3d9, D3DADAPTER_DEFAULT, &disp_mode);
ERROR_CHECK_HR(hr);
hr = IDirect3D9_GetDeviceCaps(g_d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
ERROR_CHECK_HR(hr);
/* Ask DirectX to please not clobber the FPU state when making DirectX
* API calls. This can cause libraries such as cairo to misbehave in
* certain scenarios.
*/
create_mask = 0 | D3DCREATE_FPU_PRESERVE;
/* Make sure that device access is threadsafe */
create_mask |= D3DCREATE_MULTITHREADED;
/* Determine vertex processing capabilities. Some cards have issues
* using software vertex processing. Courtesy:
* http://www.chadvernon.com/blog/resources/directx9/improved-direct3d-initialization/
*/
if ((caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
create_mask |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
/* if ((d3dcaps.DevCaps & D3DDEVCAPS_PUREDEVICE) == D3DDEVCAPS_PUREDEVICE) */
/* d3dcreate |= D3DCREATE_PUREDEVICE; */
}
else
{
create_mask |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
/* Check the filter type. */
if ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) == D3DPTFILTERCAPS_MINFLINEAR ||
(caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR) == D3DPTFILTERCAPS_MAGFLINEAR)
{
filter_type = D3DTEXF_LINEAR;
}
else
{
filter_type = D3DTEXF_NONE;
}
/* present_params.Flags = D3DPRESENTFLAG_VIDEO; */
present_params.Windowed = TRUE;
present_params.SwapEffect = D3DSWAPEFFECT_DISCARD;
present_params.BackBufferCount = 1;
present_params.BackBufferFormat = disp_mode.Format;
present_params.BackBufferWidth = 1;
present_params.BackBufferHeight = 1;
present_params.MultiSampleType = D3DMULTISAMPLE_NONE;
present_params.PresentationInterval =
D3DPRESENT_INTERVAL_DEFAULT; /* D3DPRESENT_INTERVAL_IMMEDIATE; */
hr = IDirect3D9_CreateDevice(g_d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, create_mask,
&present_params, &g_d3d_device);
if (FAILED(hr))
{
debug_info("Failed to create Direct3D9 g_d3d_device");
IDirect3D9_Release(g_d3d9);
return;
}
hr = IDirect3DDevice9_CreateOffscreenPlainSurface(g_d3d_device, 1440, 900, D3DFMT_X8R8G8B8,
D3DPOOL_DEFAULT, &g_surface, NULL);
if (FAILED(hr))
{
debug_info("Failed to create Direct3D9 g_surface");
IDirect3DDevice9_Release(g_d3d_device);
IDirect3D9_Release(g_d3d9);
return;
}
}
int main(int argc, char** argv)
{
GtkWidget* window;
GtkStack* stack;
GtkWidget* area;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request(GTK_WIDGET(window), 1440, 900);
debug_info("new window:0x%08lx\n", window);
stack = GTK_STACK(gtk_stack_new());
debug_info("new stack:0x%08lx\n", stack);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(stack));
area = gtk_drawing_area_new();
debug_info("new area:0x%08lx\n", area);
g_object_connect(area, "signal::draw", draw_event, window, "signal::realize",
drawing_area_realize, window, NULL);
gtk_stack_add_named(stack, area, "draw-area");
gtk_stack_set_visible_child(stack, area);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
/* this callback only trigger render, ignore delete_event */
g_signal_connect(window, "delete_event", G_CALLBACK(sample_render), window);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
compile use mingw64 on fedora 33
GUIPROGRAM=gtk.exe
CC=x86_64-w64-mingw32-gcc
CFLAGS=`mingw64-pkg-config --cflags gtk+-3.0`
WINLDFLAGS=-ldl `mingw64-pkg-config --libs gtk+-3.0`
WINSOURCES= main.c
all:
${CC} -o ${GUIPROGRAM} ${WINSOURCES} ${CFLAGS} ${WINLDFLAGS}
clean:
rm -fr ${GUIPROGRAM} *.o
I hope this GTK window can render correctly, how should I do?
I use other machine test. That old intel/nvidia platform work right, but the only intel HD support DX12 function level has transperency issue. I'm not sure with intel HD DX12. What should I do?