/** \fn ADMImage_To_yv12Surface */ static bool ADMImage_To_yv12Surface(ADMImage *pic, IDirect3DSurface9 *surface) { D3DLOCKED_RECT lock;; if (ADM_FAILED(IDirect3DSurface9_LockRect(surface,&lock, NULL, 0))) { ADM_warning("D3D Cannot lock surface\n"); return false; } // copy uint8_t *dst=(uint8_t *)lock.pBits; int dStride=lock.Pitch; int width=pic->GetWidth(PLANAR_Y); int height=pic->GetHeight(PLANAR_Y); d3dBlit(pic, PLANAR_Y,dst,dStride,width,height); dst+=height*dStride; d3dBlit(pic, PLANAR_U,dst,dStride>>1,width>>1,height>>1); dst+=(height/2)*(dStride/2); d3dBlit(pic, PLANAR_V,dst,dStride>>1,width>>1,height>>1); if (ADM_FAILED(IDirect3DSurface9_UnlockRect(surface))) { ADM_warning("D3D Cannot unlock surface\n"); return false; } return true; }
/** \fn displayImage_argb \brief manually do the yv12-> RGB conversion + rescale and the upload to backbuffer */ bool dxvaRender::displayImage_argb(ADMImage *pic) { IDirect3DSurface9 *bBuffer; // 1 upload to myYV12 surface if( ADM_FAILED(IDirect3DDevice9_GetBackBuffer(d3dDevice, 0, 0, D3DBACKBUFFER_TYPE_MONO, &bBuffer))) { ADM_warning("D3D Cannot create backBuffer\n"); return false; } if(!ADMImage_To_argbSurface(pic,bBuffer,scaler)) { ADM_warning("Image to argb surface failed\n"); return false; } IDirect3DDevice9_BeginScene(d3dDevice); IDirect3DDevice9_EndScene(d3dDevice); if( ADM_FAILED(IDirect3DDevice9_Present(d3dDevice, &targetRect, 0, 0, 0))) { ADM_warning("D3D Present failed\n"); } return true; }
/** \fn ADMImage_To_argbSurface */ static bool ADMImage_To_argbSurface(ADMImage *pic, IDirect3DSurface9 *surface,ADMColorScalerFull *scaler) { D3DLOCKED_RECT lock; if (ADM_FAILED(IDirect3DSurface9_LockRect(surface,&lock, NULL, 0))) { ADM_warning("D3D Cannot lock surface\n"); return false; } // RGB uint8_t *src[3]; uint8_t *dst[3]; pic->GetReadPlanes(src); dst[0]=(uint8_t *)lock.pBits; dst[1]=dst[2]=NULL; int sourcePitch[3],dstPitch[3]; pic->GetPitches(sourcePitch); dstPitch[0]=lock.Pitch; dstPitch[1]=dstPitch[2]=0; scaler-> convertPlanes(sourcePitch,dstPitch, src, dst); if (ADM_FAILED(IDirect3DSurface9_UnlockRect(surface))) { ADM_warning("D3D Cannot unlock surface\n"); return false; } return true; }
/** \fn brief input is already a surface, in yv12 format */ bool dxvaRender::displayImage_surface(ADMImage *pic,admDx2Surface *surface) { // this does not work, both surfaces are coming from different device IDirect3DSurface9 *bBuffer; POINT point={0,0}; // 1 upload to myYV12 surface if(ADM_FAILED(IDirect3DDevice9_UpdateSurface(d3dDevice, surface->surface, // src &panScan, // src rect myYV12Surface, // dst &point // where to ))) { ADM_warning("Copying surface failed, switching to non accelerated path \n"); if(!pic->hwDownloadFromRef()) { ADM_warning("Failed to download yv12 from dxva\n"); return false; } // workaround : use default non bridged path if(useYV12) { return displayImage_yv12(pic); } return displayImage_argb(pic); return false; } // upload.... if( ADM_FAILED(IDirect3DDevice9_GetBackBuffer(d3dDevice, 0, 0, D3DBACKBUFFER_TYPE_MONO, &bBuffer))) { ADM_warning("D3D Cannot create backBuffer\n"); return false; } // data are in YV12 surface, blit it to mySurface // zoom and color conversion happen there if (ADM_FAILED(IDirect3DDevice9_StretchRect(d3dDevice, myYV12Surface, NULL, bBuffer, NULL, D3DTEXF_LINEAR))) { ADM_warning("StretchRec yv12 failed\n"); } IDirect3DDevice9_BeginScene(d3dDevice); IDirect3DDevice9_EndScene(d3dDevice); if( ADM_FAILED(IDirect3DDevice9_Present(d3dDevice, &targetRect, 0, 0, 0))) { ADM_warning("D3D Present failed\n"); } return true; }
/** \fn brief input is already a surface, in yv12 format */ bool dxvaRender::displayImage_surface(ADMImage *pic,admDx2Surface *surface) { // this does not work, both surfaces are coming from different device IDirect3DSurface9 *bBuffer; POINT point={0,0}; // OK ADM_info("surface duplicated\n"); if( ADM_FAILED(D3DCall(IDirect3DDevice9,GetBackBuffer,d3dDevice, 0, 0, D3DBACKBUFFER_TYPE_MONO, &bBuffer))) { ADM_warning("D3D Cannot create backBuffer\n"); return false; } // can we directly use the surface from dxva ? (can we at all ?) if (ADM_FAILED(D3DCall(IDirect3DDevice9,StretchRect,d3dDevice, surface->surface, NULL, bBuffer, NULL, D3DTEXF_LINEAR))) { ADM_warning("StretchRec yv12 failed\n"); // go to indirect route if(!pic->hwDownloadFromRef()) { ADM_warning("Failed to download yv12 from dxva\n"); return false; } // workaround : use default non bridged path if(useYV12) { return displayImage_yv12(pic); } return displayImage_argb(pic); } IDirect3DDevice9_BeginScene(d3dDevice); IDirect3DDevice9_EndScene(d3dDevice); if( ADM_FAILED(IDirect3DDevice9_Present(d3dDevice, &targetRect, 0, 0, 0))) { ADM_warning("D3D Present failed\n"); } return true; }
/** \fn refresh \brief does not work correctly */ bool dxvaRender::refresh(void) { ADM_info("Refresh**\n"); #if 0 if( ADM_FAILED(IDirect3DDevice9_Present(d3dDevice, &targetRect, 0, 0, 0))) { ADM_warning("D3D Present failed\n"); } #else D3DCallNoArg(IDirect3DDevice9,BeginScene,d3dDevice); D3DCallNoArg(IDirect3DDevice9,EndScene,d3dDevice); if( ADM_FAILED(D3DCall(IDirect3DDevice9,Present,d3dDevice, &targetRect, 0, 0, 0))) { ADM_warning("D3D Present failed\n"); } #endif return true; }
/** \fn refresh \brief does not work correctly */ bool dxvaRender::refresh(void) { ADM_info("Refresh**\n"); #if 0 if( ADM_FAILED(IDirect3DDevice9_Present(d3dDevice, &targetRect, 0, 0, 0))) { ADM_warning("D3D Present failed\n"); } #endif return true; }
/** \fn displayImage_yv12 \brief copy image to myV12 surface then convert from yv12 to display format in mySurface */ bool dxvaRender::displayImage_yv12(ADMImage *pic) { IDirect3DSurface9 *bBuffer; // 1 upload to myYV12 surface if(!ADMImage_To_yv12Surface(pic,myYV12Surface)) { return false; } // upload.... if( ADM_FAILED(IDirect3DDevice9_GetBackBuffer(d3dDevice, 0, 0, D3DBACKBUFFER_TYPE_MONO, &bBuffer))) { ADM_warning("D3D Cannot create backBuffer\n"); return false; } // data are in YV12 surface, blit it to mySurface // zoom and color conversion happen there if (ADM_FAILED(IDirect3DDevice9_StretchRect(d3dDevice, myYV12Surface, NULL, bBuffer, NULL, D3DTEXF_LINEAR))) { ADM_warning("StretchRec yv12 failed\n"); } IDirect3DDevice9_BeginScene(d3dDevice); IDirect3DDevice9_EndScene(d3dDevice); if( ADM_FAILED(IDirect3DDevice9_Present(d3dDevice, &targetRect, 0, 0, 0))) { ADM_warning("D3D Present failed\n"); } return true; }
/** \fn setup \brief Allocate stuff for a given display with/height. It is called again each time the zoom is changed */ bool dxvaRender::setup() { D3DVIEWPORT9 viewPort = {0, 0, displayWidth, displayHeight, 0, 1}; ADM_info("D3D (re)Setting up \n"); D3DPRESENT_PARAMETERS presentationParameters; memset(&presentationParameters, 0, sizeof(presentationParameters)); presentationParameters.Windowed = TRUE; presentationParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; // We could use copy, but discard seems faster according to ms presentationParameters.Flags = D3DPRESENTFLAG_VIDEO; presentationParameters.hDeviceWindow = windowId; presentationParameters.BackBufferWidth = displayWidth; presentationParameters.BackBufferHeight = displayHeight; presentationParameters.MultiSampleType = D3DMULTISAMPLE_NONE; presentationParameters.PresentationInterval = D3DPRESENT_INTERVAL_ONE; presentationParameters.BackBufferFormat = displayMode.Format; presentationParameters.BackBufferCount = 1; presentationParameters.EnableAutoDepthStencil = FALSE; #ifndef REUSE_DEVICE if(ADM_FAILED(IDirect3D9_CreateDevice( d3dHandle, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, presentationParameters.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentationParameters, &d3dDevice))) { ADM_warning("Failed to create D3D device\n"); return false; } #else d3dDevice=admD3D::getDevice(); #endif // D3DFORMAT yv12=(D3DFORMAT)MAKEFOURCC('Y','V','1','2'); // if( ADM_FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( d3dDevice, displayWidth,displayHeight, displayMode.Format, D3DPOOL_DEFAULT, &mySurface, NULL))) { ADM_warning("D3D Cannot create surface\n"); return false; } if( ADM_FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( d3dDevice, imageWidth,imageHeight, yv12, D3DPOOL_DEFAULT, &myYV12Surface, NULL))) { ADM_warning("D3D Cannot create surface\n"); return false; } // put some defaults IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_SRCBLEND, D3DBLEND_ONE); IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_ALPHAFUNC, D3DCMP_GREATER); IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_ALPHAREF, (DWORD)0x0); IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_LIGHTING, FALSE); IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); // if(ADM_FAILED(IDirect3DDevice9_SetViewport(d3dDevice, &viewPort))) { ADM_warning("D3D Cannot set D3D viewport\n"); return false; } scaler=new ADMColorScalerFull(ADM_CS_BICUBIC,imageWidth,imageHeight,displayWidth,displayHeight, ADM_COLOR_YV12, ADM_COLOR_RGB32A ); videoBuffer=new uint8_t[displayWidth*displayHeight*4]; panScan.left =0; panScan.right =imageWidth-1; panScan.top =0; panScan.bottom=imageHeight-1; targetRect.left =0; targetRect.right =displayWidth-1; targetRect.top =0; targetRect.bottom=displayHeight-1; ADM_info("Setup done\n"); return true; }
/** \fn changeZoom */ bool dxvaRender::init( GUI_WindowInfo * window, uint32_t w, uint32_t h,renderZoom zoom) { ADM_info("Initializing dxva2/D3D render\n"); info=*window; baseInit(w,h,zoom); windowId=(HWND)window->systemWindowId; if(!d3dHandle) { ADM_warning("No D3DHandle\n"); return false; } if (ADM_FAILED(IDirect3D9_GetAdapterDisplayMode(d3dHandle, D3DADAPTER_DEFAULT, &displayMode))) { ADM_warning("Dxv2/D3D Render: Cannot get display mode\n"); return 0; } D3DCAPS9 deviceCapabilities; ADM_info("D3D Checking device capabilities\n"); if (ADM_FAILED(IDirect3D9_GetDeviceCaps(d3dHandle, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &deviceCapabilities))) { ADM_warning("Cannot get device capabilities"); return false; } int texture = deviceCapabilities.TextureCaps; ADM_info("Power of 2 : %d\n", (texture & D3DPTEXTURECAPS_POW2) && !(texture & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)); ADM_info("Square only: %d\n", (texture & D3DPTEXTURECAPS_SQUAREONLY)); // Check if we support YV12 D3DFORMAT fmt=displayMode.Format; D3DFORMAT yv12=(D3DFORMAT)MAKEFOURCC('Y','V','1','2'); if (ADM_FAILED(IDirect3D9_CheckDeviceFormatConversion( d3dHandle, // adapter D3DADAPTER_DEFAULT, // device type D3DDEVTYPE_HAL, // adapter format yv12, // render target format fmt))) // depth stencil format { useYV12=false; ADM_info("D3D YV12 not supported\n"); } else { useYV12=true; ADM_info("D3D YV12 is supported\n"); } if(!setup()) { ADM_warning("Dxva/D3D setup failed\n"); return false; } videoWidget=(ADM_Qvideo *)info.widget; videoWidget->useExternalRedraw(true); // deactivate Qt Double buffering videoWidget->setDrawer(this); ADM_info("Dxva (D3D) init successful, dxva render. w=%d, h=%d,zoom=%d, displayWidth=%d, displayHeight=%d\n",(int)w,(int)h,(int)zoom,(int)displayWidth,(int)displayHeight); return true; }