Pixel Aspect Ratio (again me)

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Pixel Aspect Ratio (again me)
by on (#127006)
Ok, im gonna describe how im doing pixel aspect ratio in windowed mode and post pics.
This envolve direct3d9. Please someone help me how to do it well.

- First i have a fuction that resizes the window to the desired client window size. Lets says SetWindowX(HWND hwnd, int x). I have tested calling after "GetClientRect()" and is resized correctly.
The body of SetWindowX() is as follow:

Code:
void SetWindowX(HWND hwnd, int x)
{
   g_WinX = x;
   RecreateD3D(hwnd, x);
   ClientResize(hwnd, 292 * x, (240 - 16) * x);
}


Are those images well point sampled and interpolated??

now i have D3D9 interface well created and "RecreateD3D()" is as follow:
Code:
int RecreateD3D(HWND hWnd, int x)
{
   ResetD3D();
   
   D3DPRESENT_PARAMETERS d3dpp;    // create a struct to hold various device information
   
   ZeroMemory(&d3dpp, sizeof(d3dpp));    // clear out the struct for use
   d3dpp.Windowed = TRUE;    // program windowed, not fullscreen
   d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    // discard old frames
    d3dpp.hDeviceWindow = hWnd;    // set the window to be used by Direct3D
   d3dpp.BackBufferCount = 1;
   d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
   d3dpp.BackBufferWidth = 292 * x;
   d3dpp.BackBufferHeight = 240 - 16;
   d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;

   g_hr = d3d->CreateDevice(D3DADAPTER_DEFAULT,
                      D3DDEVTYPE_HAL,
                      hWnd,
                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                      &d3dpp,
                      &d3ddev);

   if (FAILED(g_hr))
      return 0;

   //g_hr = d3ddev->CreateOffscreenPlainSurface(256,256, D3DFMT_X8R8G8B8 ,D3DPOOL_DEFAULT, &off_screen, 0);
   g_hr = d3ddev->CreateOffscreenPlainSurface(256,240, D3DFMT_X8R8G8B8 ,D3DPOOL_DEFAULT, &off_screen, 0);

   if (FAILED(g_hr))
      return 0;

   g_hr = d3ddev->CreateRenderTarget(256 *x * 2,(240 - 16),
D3DFMT_X8R8G8B8 ,D3DMULTISAMPLE_NONE, 0, 0, &stage_one, 0);

   if (FAILED(g_hr))
      return 0;

   g_hr = d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO,&back_buffer);

   if (FAILED(g_hr))
      return 0;
}


"ResetD3D()" just check if it has to recreate surfaces. It free up surfaces is they are created and THEN RecreateD3D() recreates all the surfaces again. I know it could be done better but its just for starting.

The biggest thing: i use StrectchRect() D3D9 interface to "blt" between surfaces. I have one "offscreen" surface of 256x240 where pixels are put in. I know basic cards doesn't handle surfaces that are not power of 2, but my Nvidia 440 can handle as well as others nvidia and ati cards.

I use this, and is my main blitting function, that blt surfaces.

Code:
RECT rcClip = {0,8,256,240 - 8};

void EndScene(void)
{
   off_screen->UnlockRect();
   g_hr = d3ddev->StretchRect(off_screen, &rcClip, stage_one, 0, D3DTEXF_POINT);
   g_hr = d3ddev->StretchRect(stage_one, 0, back_buffer, 0, D3DTEXF_LINEAR);
   g_hr = d3ddev->EndScene();    // ends the 3D scene
   g_hr = d3ddev->Present(NULL, NULL, NULL, NULL);    // displays the created frame
}

rcClip is just to crop the upper and lower 8 pixels of the image.

Now if you took a look to RecreateD3D() the Width of stage_one is multiplied by 2.

Sincerely i don't know what to do i get this:

1X:
Image


2X:
Image

3X:
Image
Re: Pixel Aspect Ratio (again me)
by on (#127337)
Anes wrote:
The biggest thing: i use StrectchRect() D3D9 interface to "blt" between surfaces. I have one "offscreen" surface of 256x240 where pixels are put in. I know basic cards doesn't handle surfaces that are not power of 2, but my Nvidia 440 can handle as well as others nvidia and ati cards.


Be that as it may, why not just make a surface of 256x256 and write to that, then disregard the bottom 16 rows?
Re: Pixel Aspect Ratio (again me)
by on (#127719)
mikejmoffitt wrote:
Anes wrote:
The biggest thing: i use StrectchRect() D3D9 interface to "blt" between surfaces. I have one "offscreen" surface of 256x240 where pixels are put in. I know basic cards doesn't handle surfaces that are not power of 2, but my Nvidia 440 can handle as well as others nvidia and ati cards.


Be that as it may, why not just make a surface of 256x256 and write to that, then disregard the bottom 16 rows?


That is what i actually do when i do gfx without "effects", but for pixel aspect ratio i use not powered 2 surfaces to simplify.
I really can't do pixel aspect ratio look good, i have tried all options for me.

The only one that gave me not too scratched graphs was having:

a) 256x240 -> 512 x 480 (with point sampling)
b) 512x480 -> 584 x 480 (with linear interpolation)
c) 584 x 480 -> back buffer (584x480)

i don't know what i do wrong.
Re: Pixel Aspect Ratio (again me)
by on (#127721)
Anes wrote:
The only one that gave me not too scratched graphs was having:

a) 256x240 -> 512 x 480 (with point sampling)
b) 512x480 -> 584 x 480 (with linear interpolation)

That's pretty much the right way to do it, unless you make your own shader that does a) and b) in one step, as in FBI.

Quote:
c) 584 x 480 -> back buffer (584x480)

Ideally you should be able to do step b) directly to the back buffer.
Re: Pixel Aspect Ratio (again me)
by on (#127722)
It's all ok but take a look at this screen shot:
Image

That's isn't normal or it is?
Re: Pixel Aspect Ratio (again me)
by on (#127725)
That's what you get for doing simple "nearest neighbor" stretching - to avoid stuff like that, you will need to do some sort of interpolation (which is likely to make things get a bit blurry).
Re: Pixel Aspect Ratio (again me)
by on (#127726)
Quietust wrote:
That's what you get for doing simple "nearest neighbor" stretching - to avoid stuff like that, you will need to do some sort of interpolation (which is likely to make things get a bit blurry).


im actually doing both: point sampling and linear interpolation. The screenshot that you see has both appplied.
Re: Pixel Aspect Ratio (again me)
by on (#127727)
That looks like an off-by-one; i.e. you have one column of pixels that has been replicated three times rather than twice at the nearest-neighbor step.

Are you scaling 255 columns to 512, or maybe 256 to 513?
Re: Pixel Aspect Ratio (again me)
by on (#127728)
lidnariq wrote:
That looks like an off-by-one; i.e. you have one column of pixels that has been replicated three times rather than twice at the nearest-neighbor step.

Are you scaling 255 columns to 512, or maybe 256 to 513?


Im i don't get it. English missunderstanding problema. Could you be more verbose??
Re: Pixel Aspect Ratio (again me)
by on (#127730)
Pretend for the moment that each letter below corresponds to a pixel:

Say you're starting with the pixels
abcdefgh

And you want to scale it up exactly by 2, using nearest neighbor. You should get
aabbccddeeffgghh.

But in software you usually specify that not as "scale this by 200%" but instead as "scale this from 8 pixels wide to 16 pixels wide"

If for some reason something goes wrong, and instead you accidentally said "scale this from 8 pixels wide to 17 pixels wide" you'd get something like this:
aabbccdddeeffgghh.

It's not necessarily the case that the code says "17" anywhere; instead there could be a problem with how floating-point positions within textures are calculated; you might need to change whether the reference point of the texture is center or top-left or ... something.
Re: Pixel Aspect Ratio (again me)
by on (#127731)
lidnariq wrote:
That looks like an off-by-one; i.e. you have one column of pixels that has been replicated three times rather than twice at the nearest-neighbor step.

Are you scaling 255 columns to 512, or maybe 256 to 513?


Im upscaling 256 to 512...
Re: Pixel Aspect Ratio (again me)
by on (#127732)
I don't understand. I suck about gfx programming, but i do:

Code:
d3ddev->StretchRect(off_screen, 0, stage_one, 0, D3DTEXF_POINT);
d3ddev->StretchRect(stage_one, 0, back_buffer, 0, D3DTEXF_LINEAR);


Where:

a) "off_screen" is -> 256x240 surface.
b) "stage_one" is 512x480 surface.
c) "back_buffer" is 584x480 surface.

What is wrong?
Re: Pixel Aspect Ratio (again me)
by on (#127733)
Perhaps what's wrong is something inside the Windows compositor. I don't remember which version of Windows or which emulator I noticed this on, but on at least one version of Windows and at least one emulator set to enlarge the video output, I would notice the picture shifting by less than one pixel when I pulled down a menu or otherwise partially obscured the gameplay surface.
Re: Pixel Aspect Ratio (again me)
by on (#127734)
Anes wrote:
What is wrong?

Probably a too specific problem to get answered. I would go about it empirically. Construct an image that only contains vertical alternating black/white lines. Put that through the first stage (point sampling), and see what the result is. Verify the result on multiple hardware/software configurations, if possible. If the results are consistent, figure out why the problem occurs and how to fix it. Even if you can't figure out the "why" part, you may be able to figure out a solution that makes sense.

StretchRect is definitely not the only option for doing this.
Re: Pixel Aspect Ratio (again me)
by on (#127738)
tepples wrote:
Perhaps what's wrong is something inside the Windows compositor. I don't remember which version of Windows or which emulator I noticed this on, but on at least one version of Windows and at least one emulator set to enlarge the video output, I would notice the picture shifting by less than one pixel when I pulled down a menu or otherwise partially obscured the gameplay surface.


You were right, the difference is exactly 1 pixel. I substracted 1 pixel width and 1 pixel height and now the image is correct. Thats correspond to GetSystemMetrics(SM_CXBORDER).

Problem solved. :)
Re: Pixel Aspect Ratio (again me)
by on (#127740)
Anes wrote:
Thats correspond to GetSystemMetrics(SM_CXBORDER).

If the result is 1, that does correspond to a bunch of things. I don't buy this explanation. But glad you got it working. (It's a bit strange, because the right and bottom coordinates of RECTs are typically exclusive on Windows.)