#271  
Old 21st June 2013, 09:20 AM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

I guess it's because, my algorithm to resize native game screen window using reported fb_width and height by the plugin, resized the window screen to 320x237, not 320x240.

So it drops 3 rows of pixels in the scaler for some reason.

IDK, I thought the "native res" (uh as I thought it existed anyway) was actually x 237 according to internal plugin res, or why would it drop 3 pixels...

*feels a stupid question answer coming on*
Reply With Quote
  #272  
Old 21st June 2013, 10:07 AM
angrylion angrylion is offline
Member
 
Join Date: Oct 2008
Location: Moscow, Russia
Posts: 36
Default

Quote:
Originally Posted by FatCat View Post
Are you saying that (VI_WIDTH_REG & 0x00000FFF) is always the correct width of the VI?
It's not a width of the VI, it's an offset in RDRAM bytes between successive lines that the VI fetches from the RDRAM and then draws.

Quote:
Originally Posted by FatCat View Post
If so, I think you could benefit more by using zilmar's `void ViWidthChanged()` to update any VI_WIDTH_REG-related things.
No, I cannot benefit from this function, because the emulator must give me its real and updated VI_WIDTH_REG value on each ProcessRDPList(), UpdateScreen() and ShowCFB() call and to this value I'm applying nothing except a single bitmask. I'm not even sure that 1964 and Mupen call ViWidthChanged() as diligently.

Quote:
Originally Posted by FatCat View Post
And you're saying there is no "native resolution" of the RDP, only the VI res?
There are 3 parameters: fb_width and horizontal and vertical scissoring coordinates in the RDP. You can try to define native resolution of the RDP from that as you want.

Quote:
Originally Posted by FatCat View Post
Then why is it that, if there's only one "native resolution" and it's the VI one, the screen ends up stretched or the pixels are stretched to fit the window, in cases where VI_WIDTH does not match calculated fb_width?
The VI does texture interpolation all the time and it doesn't know anything about fb_width in my code or on hardware.

Quote:
Originally Posted by FatCat View Post
Since (sync) is rarely true, it saves executing this code a lot of times that UpdateScreen is called, whereas on your plugin it executes constantly even when there was no change to scale_x or scale_y since the last procedural call, but also, I'm not quite at 90% sure, that my method is updating them frequently enough.
First, the VI has no floating-point capabilities, unlike your code. The fact that you recompute your scale_x and scale_y only after ViWidthChanged() is strange, because ViWidthChanged() is supposed to notify you about the change of VI_WIDTH_REG and nothing else. The fact that you resize your emulator window taking fb_width into account just doesn't represent the VI faithfully. This RDP register is not accessible to the VI.

Quote:
Originally Posted by FatCat View Post
You would rather just draw everything in 1024x768 all the time then show any possibility of a non-stretched, base raster size where base pixel dimensions aren't multiplied?
As I said, the VI does texture interpolation (stretching) all the time. Also, the idea to dynamically resize the window of an emulator seems very weird to me.

Quote:
Originally Posted by FatCat View Post
Unless you're saying only one exact resolution or aspect ratio is possible every time, surely you must have a bug with just stretching it out to 1024x768 all the time.
First, it's true, there's only one native resolution, and it is determined by VI_V_SYNC_REG, VI_H_SYNC_REG and by the standard of your TV, PAL or NTSC. It's the resolution/frequency at which the VI outputs RGB values to the video DAC. And it bound to be constant, if the VI wants to stay in sync with your TV. For NTSC, the visible area of your TV is 640x480 at most (640x525 for PAL), which I use in my PreScale array. Secondly, you obviously use the notion of a "bug" arbitrarily here, everybody is free to scale the image to whatever resolution they want.

Last edited by angrylion; 21st June 2013 at 10:47 AM.
Reply With Quote
  #273  
Old 21st June 2013, 10:55 AM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

Quote:
Originally Posted by angrylion View Post
It's not a width of the VI, it's an offset in RDRAM bytes between successive lines that the VI fetches from the RDRAM and then draws.
The way you say this makes me think:
memcpy(current_row_of_pixels, RDRAM + cur_offset, VI_WIDTH_REG & 0x00000FFF);

...But maybe that's not really what you meant, because that sounds an awful lot like the width to me, but, maybe you mean there are other things stored per row of pixels, besides the pixels themselves or something, IDK.

Quote:
Originally Posted by angrylion View Post
No, I cannot benefit from this function, because the emulator must give me its real and updated VI_WIDTH_REG value on each ProcessRDPList(), UpdateScreen() and ShowCFB() call and to this value I'm applying nothing except a single bitmask. I'm not even sure that 1964 and Mupen call ViWidthChanged() as diligently.
Then just update it within all the relevant functions.

Code:
static int sync = FALSE;

EXPORT void CALL ProcessRDPList(void) {
    sync = TRUE;
 // ...
}
EXPORT void CALL ShowCFB(void) {
    sync = TRUE;
    return;
}
EXPORT void CALL ViWidthChanged(void) {
    sync = TRUE;
    return;
}
EXPORT void CALL UpdateScreen(void) {
    if (sync) {
        Update the screen for real and updated values.
        sync = FALSE;
    }
    // rest of stuff from rdp_update could go here
}
Maybe to a degree you might have some limitations hindering this from being frequent enough, and maybe you're right, but the important thing is not the *might not be able to do*; it's the *benefit of doing*.
If successfully implemented, code that gets executed millions of times per minute, could be cut down to only execute the code not specific to just updated game resolutions and screen settings, which was only relevant when things about the screen got changed etc.

It's part of how I had to optimize the RSP.
If something seems like it would save a great deal of trouble, or latency, I look beyond what seems impossible, and find some way to approach it.

Quote:
Originally Posted by angrylion View Post
The fact that you recompute your scale_x and scale_y only after ViWidthChanged() is strange, because ViWidthChanged() is supposed to notify you about the change of VI_WIDTH_REG and nothing else.
ViWidthChanged is supposed to notify you about the change of VI_WIDTH_REG, and, indirectly not nothing else.

When this register gets changed improves the odds that the CPU is also in the process of updating at least one other register related in some way to the updated width, which makes it important to inclusively set the theoretical "sync = TRUE;" idea I was explaining before, in this function as well--not only in this function, but also.

Quote:
Originally Posted by angrylion View Post
As I said, the VI does texture interpolation (stretching) all the time. Also, the idea to dynamically resize the window of an emulator seems very weird to me.
Maybe, but window size has anything to do with neither the CPU nor the RDP.
As you said, resolution can vary based on TV size or PAL/NTSC,

Why bias it to an exact 4:3 ratio like 1024x768 to pick an exact size, among an infinitude of others you could have picked, when you could just use the software resolution to draw it at the smallest accurate resolution possible (hopefully a native res of sorts)?

JFYI, my monitor screen is 1024x768 pixels. I can't comfortably use your plugin.
I would rather have the emulator window resize itself to the smallest/native resolution possible that maintains being accurate.

You may as well make it 1024x1024 or some other ratio/max screen limit possible or something.

Quote:
Originally Posted by angrylion View Post
Secondly, you obviously use the notion of a "bug" arbitrarily here, everybody is free to scale the image to whatever resolution they want.
It might not be a "hardware bug" granted what you said about interpolation and stretching of a native screen size, to fit the TV or whatever, but on the software level you shouldn't have to unnecessarily distort the screen ratio or dimensions just because you can. There are too many different ways to do this, even if they are all fully accurate by your definition, so why not do the sensible thing and just use the base, smaller software screen size?

Maybe some config option in DllConfig could force screen dimensions to anything higher than that and apply the interpolation, like to 1024x768 for example.

Quote:
Originally Posted by angrylion View Post
It's only natural, he specifically commands his GPU driver to drop that row in an attempt to work around some strange behavior of his driver when it does DirectDraw scaled blits, see my UPDATE2 in my previous message.
(EDIT) I guess you edited this part out of your post, but according to my analysis, I would have to guess that the native VI resolution for this game is really 320x240 px, not by 237 px, I have to fix that somehow. Hopefully your advice can help.

Last edited by HatCat; 21st June 2013 at 11:16 AM.
Reply With Quote
  #274  
Old 21st June 2013, 12:02 PM
shunyuan's Avatar
shunyuan shunyuan is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Apr 2013
Posts: 491
Default

Quote:
Originally Posted by angrylion View Post
UPDATE 2: I'm very happy that this change

src.right = PRESCALE_WIDTH - 1;

allows your GPU driver to avoid inconsistent filtering and give you the picture that you want (not that I consider it accurate or inaccurate, because methods of texture filtering when doing scaled blits are undefined in DirectDraw). However, your change actually contradicts DirectDraw documentation by Microsoft. Specifically, when discussing IDirectDrawSurface7::Blt method, it says "RECT structures are defined so that the right and bottom members are exclusive—therefore, right minus left equals the width of the rectangle, not 1 less than the width". So the "bug" you, suanyuan discovered is not a bug in my code, it's a bug of your GPU driver.
Actually you misunderstand the "LPRECT lpSrcRect" parameter of DirectDraw::Blit() function in your code.

(right, bottom) is coordinate of right-bottom point, not (width, height)

Code:
HRESULT Blt(
  [in]  LPRECT lpDestRect,
  [in]  LPDIRECTDRAWSURFACE7 lpDDSrcSurface,
  [in]  LPRECT lpSrcRect,
  [in]  DWORD dwFlags,
  [in]  LPDDBLTFX lpDDBltFx
);

lpSrcRect [in]

    A pointer to a RECT structure that defines the upper-left and lower-right points of the rectangle to bitblt from on the source surface. If this parameter is NULL, the entire source surface is used.

if
lpSrcRect->left = 0
lpSrcRect->top = 0

then
lpSrcRect->right = width - 1;
lpSrcRect->bottom = height - 1;

That's why I change the code from

src.right = PRESCALE_WIDTH;

to

src.right = PRESCALE_WIDTH - 1;


I don't want to spend time to argue if this is a display driver bug or your bug. But you can double check with the DirectX SDK document and verify the change I made is correct or not.

DirectX SDK
__________________
---------------------
CPU: Intel U7300 1.3 GHz
GPU: Mobile Intel 4 Series (on board)
AUDIO: Realtek HD Audio (on board)
RAM: 4 GB
OS: Windows 7 - 32 bit

Last edited by shunyuan; 21st June 2013 at 12:11 PM.
Reply With Quote
  #275  
Old 21st June 2013, 12:16 PM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

Well suanyuan, thanks to your investigation I suppose I don't mind keeping the DirectDraw code in my fork of angrylion's plugin after all.

Still though, gotta admit, it would have been way simpler to use the SDL method.
The problem with SDL is that interpolation or screen stretching requires a bit of manual configuration on our end...but at least by default having no scaling applied to it is kind of cool.

I'd want to use either Windows GDI or SDL because they are more portable than DirectX/DirectDraw.
Microsoft more-or-less deprecated DirectDraw support anyway (at least that's what they intimidate you into thinking).

GDI can work on anybody's computer that has Windows installed, same for SDL.
It requires no video card I think, more compatible.
We do lose video memory access for faster hardware-blitting, but maybe that's not the bulk of this plugin's slowness.

Finally, we get cool functions.
An instant function for taking a screenshot of the emulated screen and writing it into a BMP file.

Makes cool features easier to add ironically.

But, hell.
Thanks to this update to DirectDraw I guess I'll let it be for now.
Reply With Quote
  #276  
Old 21st June 2013, 12:29 PM
shunyuan's Avatar
shunyuan shunyuan is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Apr 2013
Posts: 491
Default

Never mind, since I am replacing the rendering engine of my plugin with latest mess rdp.
__________________
---------------------
CPU: Intel U7300 1.3 GHz
GPU: Mobile Intel 4 Series (on board)
AUDIO: Realtek HD Audio (on board)
RAM: 4 GB
OS: Windows 7 - 32 bit
Reply With Quote
  #277  
Old 21st June 2013, 01:09 PM
angrylion angrylion is offline
Member
 
Join Date: Oct 2008
Location: Moscow, Russia
Posts: 36
Default

Quote:
Originally Posted by FatCat View Post
The way you say this makes me think:
memcpy(current_row_of_pixels, RDRAM + cur_offset, VI_WIDTH_REG & 0x00000FFF);
...But maybe that's not really what you meant, because that sounds an awful lot like the width to me, but, maybe you mean there are other things stored per row of pixels, besides the pixels themselves or something, IDK.
Nothing like that. First, you cannot represent this with memcpy(), because the VI does interpolation on every pixel. To simplify what's happening, for each VI line, the VI copies an amount of pixels, which is derived from VI_X_SCALE_REG and VI_H_START_REG and independent of VI_WIDTH_REG, starting approximately from VI_ORIGIN_REG + (line_in_VI_coordinate_space * y_add + y_start) * (VI_WIDTH_REG & 0xfff), and interpolates them to create an amount of pixels derived from VI_H_START_REG. It may copy only each second, each third pixel from the RDRAM, etc., depending on VI_X_SCALE_REG, that's another reason why memcpy() doesn't reflect the situation. It's all in my function rdp_update(), which you could have studied. Each line in VI coordinate space has a constant length (width), which is connected to VI_H_SYNC_REG and actually determined by your DAC/TV, but only 640 are visible in my imaginable capture card and much less than that on real TVs.

Quote:
Originally Posted by FatCat View Post
Then just update it within all the relevant functions.

Code:
static int sync = FALSE;

EXPORT void CALL ProcessRDPList(void) {
    sync = TRUE;
 // ...
}
EXPORT void CALL ShowCFB(void) {
    sync = TRUE;
    return;
}
EXPORT void CALL ViWidthChanged(void) {
    sync = TRUE;
    return;
}
EXPORT void CALL UpdateScreen(void) {
    if (sync) {
        Update the screen for real and updated values.
        sync = FALSE;
    }
    // rest of stuff from rdp_update could go here
}
Maybe to a degree you might have some limitations hindering this from being frequent enough, and maybe you're right, but the important thing is not the *might not be able to do*; it's the *benefit of doing*.
If successfully implemented, code that gets executed millions of times per minute, could be cut down to only execute the code not specific to just updated game resolutions and screen settings, which was only relevant when things about the screen got changed etc.
First, the code I think you're referring to can be executed 3600 times per minute at most. Second, nothing in your code above guarantees that my rdp_update() will receive proper values of VI registers and not some stale values, it's unsafe. Third, in real games UpdateScreen() is called once per each ProcessRDPList(), so you'll save nothing from this.

Quote:
Originally Posted by FatCat View Post
When this register gets changed improves the odds that the CPU is also in the process of updating at least one other register related in some way to the updated width, which makes it important to inclusively set the theoretical "sync = TRUE;" idea I was explaining before, in this function as well--not only in this function, but also.
Might make it important for an inherently inaccurate implementation which is concerned with odds and probabilities and doesn't compensate for cases when some probabilistic condition wasn't satisfied, but I don't care about such solutions in the slightest.

Quote:
Originally Posted by FatCat View Post
Why bias it to an exact 4:3 ratio like 1024x768 to pick an exact size, among an infinitude of others you could have picked, when you could just use the software resolution to draw it at the smallest accurate resolution possible (hopefully a native res of sorts)?
My TV is 4:3 btw, so I'm not sure how I bias the aspect ratio. Anyway, it's pretty easy to change rdp_update() to create a 640x480 (4:3 btw) window for NTSC games and 640x525 window for PAL games by adding some winapi functions. That might be close to what you describe. I guess 640x480 can be called a native resolution of the visible part of VI coordinate space for NTSC.

Quote:
Originally Posted by FatCat View Post
JFYI, my monitor screen is 1024x768 pixels. I can't comfortably use your plugin.
I don't care. Recompile it. You only have to change the first two global variables in main.cpp, if you want to make the window smaller.

Quote:
Originally Posted by FatCat View Post
I guess you edited this part out of your post, but according to my analysis, I would have to guess that the native VI resolution for this game is really 320x240 px, not by 237 px, I have to fix that somehow. Hopefully your advice can help.
I'm not sure what you mean by VI resolution. The VI resolution that I'm writing about definitely can't be 320x240. I don't have any advice for you. Maybe you should start with avoiding floating-point arithmetic and removing the influence of fb_width. I edited that part of my previous post, because I misunderstood what was the problem, so my comment was off the point.
Reply With Quote
  #278  
Old 21st June 2013, 01:14 PM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

Sounds good.

Me does a GDI/DirectDraw version in ANSI C,
You does a SDL version in MAME C++,
angrypimp continues upping his C99 DirectDraw plugin

Seems like a fair enough team.

EDIT: shit lol, ninja'd by angrylion response
Reply With Quote
  #279  
Old 21st June 2013, 01:16 PM
angrylion angrylion is offline
Member
 
Join Date: Oct 2008
Location: Moscow, Russia
Posts: 36
Default

Quote:
Originally Posted by suanyuan View Post
A pointer to a RECT structure that defines the upper-left and lower-right points of the rectangle to bitblt from on the source surface. If this parameter is NULL, the entire source surface is used.
You obviously failed to read my quote from DirectX 8 SDK help files. I'll repost it once again just for you: "RECT structures are defined so that the right and bottom members are exclusive—therefore, right minus left equals the width of the rectangle, not 1 less than the width".
Reply With Quote
  #280  
Old 21st June 2013, 01:51 PM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

Quote:
Originally Posted by angrylion View Post
Nothing like that. First, you cannot represent this with memcpy(), because the VI does interpolation on every pixel. To simplify what's happening, for each VI line, the VI copies an amount of pixels, which is derived from VI_X_SCALE_REG and VI_H_START_REG and independent of VI_WIDTH_REG, starting approximately from VI_ORIGIN_REG + (line_in_VI_coordinate_space * y_add + y_start) * (VI_WIDTH_REG & 0xfff), and interpolates them to create an amount of pixels derived from VI_H_START_REG. It may copy only each second, each third pixel from the RDRAM, etc., depending on VI_X_SCALE_REG, that's another reason why memcpy() doesn't reflect the situation. It's all in my function rdp_update(), which you could have studied. Each line in VI coordinate space has a constant length (width), which is connected to VI_H_SYNC_REG and actually determined by your DAC/TV, but only 640 are visible in my imaginable capture card and much less than that on real TVs.
You said "offset in RDRAM bytes between successive lines" when we were talking about VI_WIDTH_REG.

Now you're saying that pixels in each VI line are "independent to VI_WIDTH_REG".
Does this mean pixels are not copied from RDRAM?

As if that wasn't in the least bit confusing.
And yes, I could have studied all of your code first, but I studied the portion that I was able to make out enough that I could rewrite to my preferred syntax so I can read it better while I'm focusing more on optimizations.

Quote:
Originally Posted by angrylion View Post
First, the code I think you're referring to can be executed 3600 times per minute at most. Second, nothing in your code above guarantees that my rdp_update() will receive proper values of VI registers and not some stale values, it's unsafe. Third, in real games UpdateScreen() is called once per each ProcessRDPList(), so you'll save nothing from this.
I personally have sync = TRUE set, at the moment only for ViWidthChanged.
This might be surprising to you, but anytime the game changes scenes into a different emulated aspect ratio or what I think to be a new emulated resolution, the window is successfully resized every time.

Does that totally not make sense, just because native resolution is calculated totally independent away from VI_WIDTH_REG?
No, because if the CPU is changing VI_WIDTH_REG, it most likely is changing (but this might be the part I can't guarantee, so your second point is possibly held) the other registers like SCALE and SYNC to adjust to the new VI_WIDTH_REG.

I have traced VI register values in-between successive zilmar-spec function calls.

In-between ViWidthChanged() and the next zilmar-spec function called right after it, my debugger revealed to me that VI_WIDTH_REG was, by far, not at all the only register that got changed. It was just the only register that got changed during merely the time frame of the ViWIdthChanged procedure.

But still, you're probably right that it revolves around a degree of assumption.
And 3600 times / minute = 60 times per second is not really that rapidly compare to maybe some other things, so I guess it would outweigh the deal for me to just revert it back to the way you put it in when I get the chance.

Quote:
Originally Posted by angrylion View Post
My TV is 4:3 btw, so I'm not sure how I bias the aspect ratio.
Paradox.
You answer a claim to bias with a measurement of one particular TV you know.

Not every TV is 4:3, not every game uses 4:3, and not every TV is 1024x768.

Quote:
Originally Posted by angrylion View Post
Anyway, it's pretty easy to change rdp_update() to create a 640x480 (4:3 btw) window for NTSC games and 640x525 window for PAL games by adding some winapi functions. That might be close to what you describe. I guess 640x480 can be called a native resolution of the visible part of VI coordinate space for NTSC.
Why would I want to do that? My fork already resizes the window to smallest native resolution (or so attempts).


If I want to do a sprite rip of a character and make a PNG/GIF out of it, am I going to take a screenshot of the game on your [accurately on the hardware] stretched and possibly distorted DirectDraw render?

No, I am going to request an active availability to see the software-accurate native render of the screen in native resolution where possible so that my sprite rip I make is accurate.

It is not an option with your original code, and I don't need it to be because I have it implemented in my fork. :P

Quote:
Originally Posted by angrylion View Post
I don't care. Recompile it. You only have to change the first two global variables in main.cpp, if you want to make the window smaller.
(You think I'm doing a fork for nothing? )

Lowering your forced resolution from 1024x768 is equally as pointless as it being fixed to any particular resolution in the first place.
If I make it 640x480 I'm basically following your example, except with a smaller screen.

Maybe I also potentially lose sync with your future revisions by rebelling against a static choice of 1024x768 just for the reason of my monitor size.
I have a bigger and better reason, and that's the possible need for a native, un-scaled render of the resolution on VI (e.g. for accurate sprite rips, nice and tidy screen captures etc.).

Quote:
Originally Posted by angrylion View Post
I'm not sure what you mean by VI resolution. The VI resolution that I'm writing about definitely can't be 320x240. I don't have any advice for you. Maybe you should start with avoiding floating-point arithmetic and removing the influence of fb_width. I edited that part of my previous post, because I misunderstood what was the problem, so my comment was off the point.
When I said "I hope your advice helps" I meant the advice you gave me earlier about using the two SYNC registers and, some other thing, for deriving the native resolution on the video interface.

As for the floating-point arithmetic and fb_width, those implementations were things I copied from what I learned from Glide64 and MESS, hastily into your plugin. It was not meant to be a finalized version; I just lost the modernized version changes I made that conformed to your plugin better.

But yes, there's no evidence of needing the floating-point stuff. I should remove that.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump


All times are GMT. The time now is 10:47 PM.


Powered by vBulletin® Version 3.7.3
Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.