How to use DirectX3D render gtk window on window platform?

53 Views Asked by At

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?

0

There are 0 best solutions below