Trending Games | ArcheAge | WildStar | Elder Scrolls Online | Archlord 2

  Network:  FPSguru RTSguru
Login:  Password:   Remember?  
Show Quick Gamelist Jump to Random Game
Members:2,798,158 Users Online:0
Games:723  Posts:6,195,742
Recent forum postsRSS
Active threads
Cloud view
List all forums
General Forums
Developers Corner General Discussion
Popular Game Forums
Click a status to find game forum
Game Forums
Click a letter to find game forum
A-C
2029 Online 2112: Revolution 2Moons 4Story 8BitMMO 9 Dragons A Mystical Land A Tale in the Desert III A3 ACE Online ARGO Online Aberoth Absolute Force Online Absolute Terror Achaea Adellion Aerrevan Aetolia, the Midnight Age Age of Armor Age of Conan Age of Empires Online Age of Mourning Age of Wulin Age of Wushu Aida Arenas Aika Aion Albion Online Alganon All Points Bulletin (APB) Allods Online Altis Gates Amazing World Anarchy Online Ancients of Fasaria Andromeda 5 Angels Online Anime Trumps Anmynor Anno Online Applo Arcane Hearts Arcane Legends ArchLord ArcheAge Archeblade Archlord X Asda 2 Asda Story Ashen Empires Asheron's Call Asheron's Call 2 Astera Online Astonia III Astro Empires Astro Lords: Oort CLoud Asura Force Atlantica Online Atriarch Aura Kingdom Aurora Blade Auto Assault Avatar Star Battle Dawn Battle Dawn Galaxies Battle for Graxia Battle of 3 Kingdoms Battle of the Immortals Battlecruiser Online Battlestar Galactica Online Battlestar Reloaded Beyond Protocol Black Aftermath Black Desert Black Gold Black Prophecy Black Prophecy Tactics: Nexus Conflict Blacklight Retribution Blade & Soul Blade Hunter Blade Wars Blazing Throne Bless Blitz 1941 Blood and Jade Bloodlines Champions Bounty Bay Online Brain Storm Brawl Busters. Brick-Force Bright Shadow Bullet Run Business Tycoon Online CTRacer Cabal Online Caesary Call of Camelot Call of Gods Call of Thrones Camelot Unchained Canaan Online Cardmon Hero Cartoon Universe CasinoRPG Castle Empire Castlot Celtic Heroes Champions Online Champions of Regnum Chaos Online Chrono Tales Citadel of Sorcery CitiesXL Citizen Zero City of Decay City of Heroes City of Steam City of Transformers City of Villains Civilization Online Clan Lord Clash of Clans Cloud Nine Club Penguin Colony of War Command & Conquer: Tiberium Alliances Company of Heroes Online Conquer Online Conquer Online 3 Continent of the Ninth (C9) Core Blaze Core Exiles Corum Online Craft of Gods Crimecraft Crimelife 2 Cronous Crota II Crusaders of Solaris Cultures Online Cyber Monster 2 Céiron Wars
D-F
D&D Online DC Universe DK Online DOTA DOTA 2 DUST 514 DV8: Exile Dalethaan Dance Groove Online Dark Age of Camelot Dark Ages Dark Legends Dark Orbit Dark Relic: Prelude Dark Solstice Dark and Light DarkEden Online DarkSpace Darkblood Online Darkest Dungeon Darkfall Darkfall: Unholy Wars Darkwind: War on Wheels Das Tal Dawn of Fantasy Dawntide DayZ Dead Earth Dead Frontier Deco Online Deepworld Defiance Deicide Online Dekaron Demons at the Horizon Desert Operations Destiny Diablo 3 Diamonin Digimon Battle Dino Storm Disciple Divergence Divina Divine Souls Dofus Dominus Online Dragon Ball Online Dragon Born Online Dragon Crusade Dragon Empires Dragon Eternity Dragon Nest Dragon Oath Dragon Pals Dragon Raja Dragon's Call Dragon's Call II Dragon's Prophet DragonSky DragonSoul Dragona Dragonica Dragons and Titans Dream of Mirror Online Dreamland Online Dreamlords: The Reawakening Drift City Duels Dungeon Blitz Dungeon Fighter Online Dungeon Overlord Dungeon Party Dungeon Rampage Dungeon Runners Dynastica Dynasty Warriors Online Dynasty of the Magi EIN (Epicus Incognitus) EVE Online Earth Eternal Earth and Beyond Earthrise Eclipse War Ecol Tactics Online Eden Eternal Edge of Space Einherjar - The Viking's Blood Elder Scrolls Online Eldevin Elf Online Elite: Dangerous Embers of Caerus Emil Chronicle Online Empire Empire & State Empire Craft Empire Universe 3 EmpireQuest Empires of Galldon End of Nations Endless Ages Endless Blue Moon Online Endless Online Entropia Universe EpicDuel Erebus: Travia Reborn Eredan Eternal Blade Eternal Lands Eternal Saga Ether Fields Ether Saga Online Eudemons Online EuroGangster EverEmber Online EverQuest Next EverQuest Online Adventures Evernight Everquest Everquest II Evony Exarch Exorace F.E.A.R. Online Face of Mankind Fairyland Online Fall of Rome Fallen Earth Fallen Sword Fallout Online Family Guy Online Fantage Fantasy Earth Zero Fantasy Realm Online Fantasy Tales Online Fantasy Worlds: Rhynn Faunasphere Faxion Online Ferentus Ferion Fiesta Online Final Fantasy XI Final Fantasy XIV: A Realm Reborn Firefall Fists of Fu Florensia Flyff Football Manager Live Football Superstars Force of Arms Forge Forsaken World Fortnite Fortuna Forum for Discussion of Everlight Freaky Creatures Free Realms Freesky Online Freeworld Fung Wan Online Furcadia Fury Fusion Fall
G-L
GalaXseeds Galactic Command Online Game of Thrones: Seven Kingdoms Gameglobe Gate To Heavens Gates of Andaron Gatheryn Gauntlet Gekkeiju Online Ghost Online Ghost Recon Online Gladiatus Glitch Global Agenda Global Soccer Gloria Victis Glory of Gods GoGoRacer Goal Line Blitz Gods and Heroes GodsWar Online Golemizer Golf Star GoonZu Online Graal Kingdoms Granado Espada Online Grand Chase Grand Fantasia Grepolis Grimlands Guild Wars Guild Wars 2 Guild Wars Factions Guild Wars Nightfall H1Z1 Habbo Hotel Hailan Rising HaloSphere2 Haven & Hearth Hawken Hearthstone: Heroes of Warcraft Helbreath Hellgate Hellgate: London Hello Kitty Online Hero Online Hero Zero Hero's Journey Hero: 108 Online HeroSmash Heroes & Generals Heroes in the Sky Heroes of Bestia Heroes of Gaia Heroes of Might and Magic Online Heroes of Thessalonica Heroes of Three Kingdoms Heroes of the Storm Hex Holic Online Hostile Space Hunter Blade Huxley Illutia Illyriad Immortals USA Imperator Imperian Inferno Legend Infestation: Survivor Stories Infinite Crisis Infinity Infinity Iris Online Iron Grip: Marauders Irth Worlds Island Forge Islands of War Istaria: Chronicles of the Gifted Jade Dynasty Jagged Alliance Online Juggernaut Jumpgate Jumpgate Evolution KAL Online Kakele Online Kaos War Karos Online Kartuga Kicks Online King of Kings 3 Kingdom Heroes Kingdom Under Fire II Kingdom of Drakkar Kingory Kings and Legends Kings of the Realm KingsRoad Kitsu Saga Kiwarriors Knight Age Knight Online Knights of Dream City Kothuria Kung Foo! Kunlun Online L.A.W. LEGO Universe La Tale Land of Chaos Online Landmark Lands of Hope: Phoenix Edition LastChaos League of Angels League of Legends - Clash of Fates Legend of Edda: Vengeance Legend of Golden Plume Legend of Katha Legend of Mir 2 Legend of Mir 3 Legendary Champions Lego Minifigures Online Life is Feudal Light of Nova Lime Odyssey Line of Defense Lineage Lineage Eternal: Twilight Resistance Lineage II Linkrealms Loong Online Lord of the Rings Online Lords Online Lost Saga Lucent Heart Lunia Lusternia: Age of Ascension Luvinia World
M-Q
MU Online Mabinogi Maestia: Rise of Keledus MagiKnights Magic Barrage Magic World Online Manga Fighter MapleStory Martial Heroes Marvel Heroes Marvel Super Hero Squad Online Marvel: Avengers Alliance MechWarrior Online Megaten Meridian 59 : Evolution Merlin MetalMercs Metaplace Metin 2 MicroVolts Midkemia Online Might & Magic Heroes: Kingdoms MilMo Minecraft Mini Fighter Minions of Mirth Ministry of War Monato Esprit Monkey King Online Monkey Quest Monster & Me Monster Madness Online MonsterMMORPG Moonlight Online: Tales of Eternal Blood Mordavia Mortal Online Mourning My Lands Myst Online: URU Live Myth Angels Online Myth War Myth War 2 Mytheon Mythic Saga Mythos N.E.O Online NIDA Online Nadirim Naviage: The Power of Capital Navy Field Need for Speed World Nemexia Neo's Land NeoSteam Neocron Nether Neverwinter Nexus: The Kingdom Of The Winds NinjaTrick NosTale Novus Aeterno Oberin Odin Quest Odyssey RPG Ogre Island Omerta 3 Online Boxing Manager Onverse Order & Chaos Online Order of Magic Original Blood Origins Return Origins of Malu Orion's Belt Otherland Forums OverSoul Overkings Oz Online Oz World Pandora Saga Pantheon: Rise of the Fallen Panzar Parabellum Parallel Kingdom Parfait Station Path of Exile Pathfinder Online Perfect World Perpetuum Online Phantasy Star Online 2 Phantasy Star Universe Phoenix Dynasty Online Phylon Pi Story Picaroon Pirate Galaxy Pirate Storm Pirate101 PirateKing Online Pirates of the Burning Sea Pirates of the Caribbean Online Pixie Hollow Planeshift Planet Arkadia Planet Calypso PlanetSide 2 Planetside Planets³ Playboy Manager Pocket Legends Pockie Ninja Pockie Pirates Pockie Saints PoxNora Prime World Prime: Battle for Dominus Priston Tale Priston Tale II Prius Online Project Blackout Project Powder Project Titan Forums Project Wiki Puzzle Pirates Quickhit Football
R-S
R2 Online RAN Online RF Online ROSE Online Rage of 3 Kingdoms Ragnarok Online Ragnarok Online II RaiderZ Rakion Rappelz RappelzSEA Ravenmarch Realm Fighter Realm of the Mad God Realm of the Titans Realms Online Reclamation Red Stone Red War: Edem's Curse Regnum Online Remnant Knights Renaissance Repulse Requiem: Memento Mori Rift RiotZone Rise Rise of Dragonian Era Rise of Empire Rise of the Tycoon Rising of King Risk Your Life Rivality Rockfree Rohan: Blood Feud Role Play Worlds Roll n Rock Roma Victor Romadoria Rosh Online Roto X Rubies of Eventide Ruin Online Rumble Fighter Runes of Magic Runescape Rust Rusty Hearts Ryzom S4 League SAGA SD Gundam Capsule Fighter Online SMITE SUN Sagramore Salem SaySayGirls Scarlet Blade Scions of Fate Seal Online: Evolution Second Life Secret of the Solstice Seed Serenia Fantasy Seven Seas Saga Seven Souls Online Sevencore Shadow of Legend Shadowbane Shadowrun Online Shaiya Shards Online Shattered Galaxy Sho Online Shot Online Shroud of the Avatar SideQuest Siege on Stars Sigonyth: Desert Eternity Silkroad Online Skyblade Skyforge SmashMuck Champions Smoo Online Soldier Front Soul Master Soul Order Online Soul of Guardian Space Heroes Universe Sparta: War of Empires Spellcasters Sphere Spiral Knights Spirit Tales Splash Fighters Squad Wars Star Citizen Star Sonata 2 Star Stable Star Supremacy Star Trek Online Star Trek: Infinite Space Star Wars Galaxies Star Wars: Clone Wars Adventures Star Wars: The Old Republic StarQuest Online Stargate Worlds Starlight Story Starpires State of Decay SteelWar Online Stone Age 2 Stormfall: Age of War Storybricks Stronghold Kingdoms Sudden Attack Supremacy 1914 Supreme Destiny Sword Girls Sword of Destiny: Rise of Aions SwordX Swords of Heavens Swordsman
T-Z
TERA TS Online Tabula Rasa Tactica Online Tales Runner Tales of Fantasy Tales of Pirates Tales of Pirates II Tales of Solaris Talisman Online Tamer Saga Tank Ace Tantra Online Tatsumaki: Land at War Terra Militaris TerraWorld Online Thang Online The 4th Coming The Agency The Aurora World The Black Watchmen The Chronicle The Chronicles of Spellborn The Crew The Division The Hammers End The Legend of Ares The Lost Titans The Matrix Online The Mighty Quest for Epic Loot The Missing Ink The Mummy Online The Myth of Soma The Pride of Taern The Realm Online The Repopulation The Secret World The Sims Online The Strategems The West Theralon There Therian Saga Thrones of Chaos Tibia Tibia Micro Edition Tiger Knight Titan Siege Titans of Time Toontown Online Top Speed Topia Online Torchlight Total Domination Transformers Universe Traveller AR Travia Online Travian Trials of Ascension Tribal Hero Tribal Wars Tribes Universe Trickster Online Trove Troy Online True Fantasy Live Online Turf Battles Twelve Sky Twelve Sky 2 Twilight War Tynon U.B. Funkeys UFO Online URDEAD Online Ultima Forever: Quest for the Avatar Ultima Online Ultima X: Odyssey Ultimate Naruto Ultimate Soccer Boss Uncharted Waters Online Undercover 2: Merc Wars Underlight Unification Wars Universe Online Utopia Valkyrie Sky Vampire Lord Online Vanguard: Saga of Heroes Vanquish Space Vector City Racers Vendetta Online Victory - Age of Racing Vindictus Virtonomics Vis Gladius Visions of Zosimos VoidExpanse Voyage Century Online W.E.L.L. Online WAR (Warhammer Online) WAR2 Glory WYD Global Wakfu War Thunder War of 2012 War of Angels War of Legends War of Mercenaries War of Thrones War of the Immortals WarFlow Waren Story Wargame1942 Warhammer 40,000: Eternal Crusade Warhammer 40K: Dark Millennium Online Warhammer Online: Wrath of Heroes Warkeepers Warrior Epic Wartune WebLords Wild West Online WildStar Wind of Luck WindSlayer 2 Wings of Destiny Wish Wizard101 Wizardry Online Wizards and Champions Wonder King Wonderland Online World Golf Tour World of Battles World of Darkness World of Heroes World of Kung Fu World of Pirates World of Speed World of Tanks World of Tanks Generals World of Warcraft World of Warplanes World of Warships World of the Living Dead WorldAlpha Wurm Online Xenocell Xiah Xsyon Xulu YS Online Yitien ZU Online Zentia Zero Online Zero Online: The Andromeda Crisis Zodiac Online Zombies Ate My Pizza eRepublik

MMORPG.com Discussion Forums

General Discussion

General Discussion 

Hardware  » How often does a 60 Hz monitor refresh?

2 Pages 1 2 » Search
31 posts found
  Quizzical

Guide

Joined: 12/11/08
Posts: 13180

 
OP  1/14/13 12:56:44 PM#1

The obvious answer is, 60 times per second.  That's what 60 Hz means, after all.  (Hz as units is the inverse of seconds.)  That, interestingly enough, seems to be the wrong answer.

To give some background, I've been programming a game, and thought it would be nice to keep a steady frame rate.  If your monitor refreshes every 1/60 of a second, then you'd ideally like to grab the state of the game and use it to render a frame every 1/60 of a second, and have that be what the monitor uses for the new frame.  That will give you very smooth animations.

There are a variety of problems here, though.  I was originally worried about screen tearing.  So I tried some artificial examples to try to create screen tearing, and couldn't do it.  I concluded that some sort of vertical sync is implicitly implemented in what I'm using (JOGL+Windows 7+Radeon HD 5850), most likely in video drivers.  So far, so good.

Knowing that, it would be ideal to start a frame so that it finishes just before the monitor grabs a frame.  If every frame finishes a millisecond before the monitor grabs a frame rather than a millisecond after, then that reduces your display latency by about 15 ms.

The next issue is that you can't control exactly how long it takes to render a frame.  How long it takes depends on what graphical settings are in use, how much needs to be drawn in that frame, whether textures are being generated at the same time, what other (non-game) processes are running in the background, how Windows decides to schedule threads, when Java decides to run garbage collection, and a variety of other things.

Ideally, you'd like to start a frame exactly as often as the monitor grabs a frame, and then always have the frame you start finish by the time the monitor grabs a frame.  Obviously, on slow hardware, you just have to draw as fast as you can and it's done whenever it's done.  But on faster hardware, if you can get 300 frames per second, it should be possible to be a little more precise.  If the time to draw a frame varies by a few milliseconds on fast hardware (let's say 99% of frames with 2 ms of the median), then you could move the start time up so that nearly all frames finish within several millseconds before the monitor grabs a new frame.

What you really don't want to do is to have an average frame finish as the monitor grabs a new frame, so that about half of the frames are done before it and half after.  If one frame finishes slightly after the monitor grabs a new frame, and then next slightly before, then the first frame won't display at all.  Instead, the frame before it just displays twice consecutively.  One worst case scenario is that it leads to a steady 30 frames per second rather than 60, as every other frame gets skipped.  Another worst case scenario is that the frames finish late-late-early, and then that cycle repeats forever.  That gets you 40 frames per second, but stuttering so that one frame is displayed for a full 1/30 of a second before the next frame that shows the state of the game world as of only 1/60 of a second later is displayed.  Then the next frame is only displayed for 1/60 of a second, before it is replaced by a new frame that shows the state of the world 1/30 of a second later.

One way to avoid that is to just let a fast card render as fast as it can.  That will definitely get you a new frame displayed every 1/60 of a second with only rare exceptions, and each new frame displayed will usually show the state of the game world about 13-20 ms after the last, though it will vary substantially.  But that seems less than ideal, as it would be nice for each new frame to show the same amount of time passing in the game world.  It also seems like an undue strain on hardware.

To do better than that requires knowing when the video card will grab a frame.  I speculated that what it does is, when it's time to display a new frame, it copies the most recently completed framebuffer elsewhere to feed to the monitor before continuing to render the frame currently being worked on.  Copying that completed framebuffer should take time, and make the frame take a little longer than most to render.

For long frames, that could amount to a rounding error.  But for very fast frames, it should be detectable.  So let's create a program that renders frames very fast:  a solid red screen one frame, then solid blue the next, and cycle back and forth each frame.  Then we can ask how long it took to render each frame, and see if there are outliers.

A little trial and error found that most frames took about 200 microseconds.  If I flagged frames that took more than 400 microseconds and recorded the time at which they finished, there was one such frame every 16-17 milliseconds, plus a handful of other frames that sporadically took longer than expected.  Bingo.  That's exactly what I was looking for, and would expect if copying the framebuffer to send it to the monitor did make a frame take longer.  (Actually sending the frame to the monitor will take several milliseconds; I think it just copies the frame that it is going to send somewhere else on the video card so that it won't be overwritten while it is sending it.)

Discarding the other frames that took longer was easy enough:  check the time that a frame finished as compared to the frame before it and the frame after.  If either of the time gaps differs from the time to draw a frame by more than 100 microseconds, then discard it.  This will actually discard about 2/3 of the data output, but that still leaves plenty--and with good certainty that what remains really does correspond to when the monitor draws a new frame.

We can then take the times that we know that a frame was drawn, mod out by the amount of time it takes to draw a frame, and see whether it's drawing a frame at, say, 1:35:49.0000, then 1:35:49.0167, then 1:35:49.0333, and so forth, or those plus two milliseconds, or whatever.  Let the program run for a couple of minutes to generate thousands of data points and we can average them to nail it down.

But then something unexpected happened:  the time shift drifted on the data.  Early data points might be 8 ms past, then they slowly down up to 7 ms, then 6 ms, and so forth.  Changing the assumption on how long it takes to draw a frame was able to correct the drift.  And furthermore, it was able to pin down how long it takes to actually draw a frame.  In my first data set, it came to 16661408 ns per frame.  A perfect 60 Hz would be about 16666667 ns per frame.

There's also the question of just how precise that 16661408 ns figure is.  Java's System.nanoTime() can only report times with about 300-400 ns precision.  (The precision actually varies by hardware, but that's what it is on my computer.  I've tested it.)  Averaging a large number of measurements should make it possible to get better precision, and I had data from thousands of frames.  Rather than trying to compute how good the data ought to be theoretically, I decided to just take another independent data set, run the same computations, and see how close it was to the first number.

So I did.  16661408 ns.  Again.  Another data set?  This one came to 16661406 ns.  A fourth also gave me 16661406 ns.  Those four numbers are all rounded to the nearest nanosecond, as trying to put a decimal point on it would be dubious.  But that's pretty precise, and I've pinned down the average time per frame to within a few nanoseconds.  (The time that a given frame takes to display probably varies by a lot more than a few nanoseconds, so I'm really only getting the average.)

But 16661408 ns definitely isn't the 16666667 ns of a perfect 60 frames per second.  In fact, if I've got it to within a few nanoseconds like I think I do, being off from the theoretical expectation by several thousand nanoseconds is pretty conclusive evidence that the theoretical expectation is measurably wrong.

Now, it's only off by about 0.03%.  But as keeping time goes, being off by 0.03% is horrible.  If a clock is off by 0.03%, that's more than two hours per year.  So I thought, maybe the problem is that Java's System.nanoTime() simply runs at the wrong speed.  System.nanoTime() isn't meant to tell you the time of day.  It's a relative time that is meant to tell you that 5.983 milliseconds passed between this time and that time, give or take a microsecond or so.  I think it's based on how many CPU clock cycles have passed, or something to that effect, but I'm not sure about that.

What if I run the same experiment with System.currentTimeMillis()?  That's Java's way of returning the current system time, as it gives you the number of milliseconds since midnight on January 1, 1970.  Unlike System.nanoTime(), this one is meant to tell you the time of day.

The problem with System.currentTimeMillis() is that the time it returns is some integer number of milliseconds.  At best, it's rounded to the nearest millisecond, and it could easily be rounded badly.  It's not meant to distinguish between whether 5 ms or 6 ms passed between this event and that one.  On older computers, it might only offer precision of 10 or 15 ms.  Can that really measure differences of a few microseconds, even if we average a lot of data?

Well, I've worked out the methods for System.nanoTime(), so let's run the same computations (using System.nanoTime() to measure the length of a frame, and outputting System.currentTimeMillis() when we flag a long frame) and try it again.  This time, I check the time that each frame is done, and if it's 15-18 ms after the previous one and 15-18 ms before the next, I keep it.  If not I discard it.  This ends up discarding perhaps 1/4 of my data.

So I run the same computations and get 16661594 ns per frame.  That's different from what I got with System.nanoTime(), of course.  I'm skeptical that those last few digits are significant, but I'm not really sure how precise it is.  So let's get another data set and try it again.  16661614 ns per frame.  Again?  16661660 ns per frame.  Then 16661554 ns per frame.

So it looks like using System.currentTimeMillis() to flag the long frames can really only pin down the time per frame to within about 100 ns accuracy.  But that's still enough to say that it's definitely not 16666667 ns per frame.  And it's enough to say that the result is probably different from that of System.nanoTime().  It's only off from System.nanoTime() by about 0.001% or so, which comes to several minutes per year.  As keeping time goes, being off by several minutes per year isn't great, but it's not terrible, either.  The wall clock in my bathroom is off by more than that.

I can test whether my calculations are correct more directly by using the test I described earlier.  But instead of switching the color once per time that the monitor grabs a frame, let's try switching it twice.  Let's stay we start at red, and the monitor grabs a frame.  We switch to blue, then switch back to red, and the monitor grabs a frame, so it stays red.  If you render a frame twice as fast as the monitor grabs one, then every frame the monitor grabs should be the same color.

So let's try making the monitor wait after it renders each frame by an amount that we scale to try to make it render a new frame exactly twice as fast as the monitor grabs one.  With an initial, naive guess of 8333333 ns per frame, the screen appears solid red for a while, then flickers back and forth between red and blue rapidly, then settles on blue for a while, then flickers back and forth, then returns to red for a while.  This pattern repeats indefinitely.

If we change it from 8333333 ns per frame to 8331000 ns per frame or 8330000 ns per frame, we get the same behavior, but it takes a lot longer to switch from one to the other.  At 8330700 ns per frame, it stays solid blue for a long time.  Bingo.  The amount of time it takes between moments that the monitor grabs a new frame is right around double that.

Let's return to the title.  How often does a 60 Hz monitor refresh?  It could easily vary by the monitor, video card, motherboard, and who knows what else.  But in my case, at least, it's definitely not 60 times per second.  60.02 times per second is much closer.

  Sandbox

Novice Member

Joined: 8/23/06
Posts: 309

1/14/13 2:07:19 PM#2

If you have a CRT monitor, the timing is determind by the video source and not by the monitor. You have both horizontal and vertical sync pulses and blanking periods etc.

Most video cards are able to react on vertical sync interrupt signals and update/switch the framebuffer during this period.

Use verical sync signals and double buffers to avoid the tearing.

Framerate conversion generated stuttering, like 40 hz to 60 hz i mostly an issue if you have continious movements. Most games have variation in their generated framerate but that are handled by modern GPUs.

Back to your question, you have to meassure the syncpulses from the videoboard to get a correct answer.

  Quizzical

Guide

Joined: 12/11/08
Posts: 13180

 
OP  1/14/13 2:21:07 PM#3
Originally posted by Sandbox

If you have a CRT monitor, the timing is determind by the video source and not by the monitor. You have both horizontal and vertical sync pulses and blanking periods etc.

Most video cards are able to react on vertical sync interrupt signals and update/switch the framebuffer during this period.

Use verical sync signals and double buffers to avoid the tearing.

Framerate conversion generated stuttering, like 40 hz to 60 hz i mostly an issue if you have continious movements. Most games have variation in their generated framerate but that are handled by modern GPUs.

Back to your question, you have to meassure the syncpulses from the videoboard to get a correct answer.

As best as I can tell, OpenGL does not have any vertical sync capabilities built into the API.  It does use double-buffering by default, though.

I'm using an LCD monitor, not a CRT.  Actually two LCD monitors, but the red/blue flashing test found that when they get a new frame, they both get the framebuffer as it existed at exactly the same time.

And I do think I have a correct answer for my hardware.  It seems likely that my method could find the answer for a lot of other hardware, too, though I don't know.  I posted this largely because I thought it was interesting.

  Sandbox

Novice Member

Joined: 8/23/06
Posts: 309

1/14/13 2:37:17 PM#4
Originally posted by Quizzical
Originally posted by Sandbox

If you have a CRT monitor, the timing is determind by the video source and not by the monitor. You have both horizontal and vertical sync pulses and blanking periods etc.

Most video cards are able to react on vertical sync interrupt signals and update/switch the framebuffer during this period.

Use verical sync signals and double buffers to avoid the tearing.

Framerate conversion generated stuttering, like 40 hz to 60 hz i mostly an issue if you have continious movements. Most games have variation in their generated framerate but that are handled by modern GPUs.

Back to your question, you have to meassure the syncpulses from the videoboard to get a correct answer.

As best as I can tell, OpenGL does not have any vertical sync capabilities built into the API.  It does use double-buffering by default, though.

I'm using an LCD monitor, not a CRT.  Actually two LCD monitors, but the red/blue flashing test found that when they get a new frame, they both get the framebuffer as it existed at exactly the same time.

And I do think I have a correct answer for my hardware.  It seems likely that my method could find the answer for a lot of other hardware, too, though I don't know.  I posted this largely because I thought it was interesting.

Even LCD monitors have frame rate specification, mostly due the bandwidth limitations. One difference is they don’t have to clear the screen like a CRT monitor since they have no phosphor. But it’s still the video card that dictate the data rate and the timing, and that’s why you can have a vertical sync interrupt even with a LCD connected.

I just wanted to put your attention at the right direction since you seem to lack some basic understanding of video systems; my reply was in no way a complete explanation.

Maybe this can help you… http://www.tweakguides.com/Graphics_7.html

  Loktofeit

Elite Member

Joined: 1/13/10
Posts: 11927

Currently playing EVE, SMITE, Wildstar, and Combat Arms

1/14/13 2:58:39 PM#5
Originally posted by Sandbox
Originally posted by Quizzical
Originally posted by Sandbox

If you have a CRT monitor, the timing is determind by the video source and not by the monitor. You have both horizontal and vertical sync pulses and blanking periods etc.

Most video cards are able to react on vertical sync interrupt signals and update/switch the framebuffer during this period.

Use verical sync signals and double buffers to avoid the tearing.

Framerate conversion generated stuttering, like 40 hz to 60 hz i mostly an issue if you have continious movements. Most games have variation in their generated framerate but that are handled by modern GPUs.

Back to your question, you have to meassure the syncpulses from the videoboard to get a correct answer.

As best as I can tell, OpenGL does not have any vertical sync capabilities built into the API.  It does use double-buffering by default, though.

I'm using an LCD monitor, not a CRT.  Actually two LCD monitors, but the red/blue flashing test found that when they get a new frame, they both get the framebuffer as it existed at exactly the same time.

And I do think I have a correct answer for my hardware.  It seems likely that my method could find the answer for a lot of other hardware, too, though I don't know.  I posted this largely because I thought it was interesting.

Even LCD monitors have frame rate specification, mostly due the bandwidth limitations. One difference is they don’t have to clear the screen like a CRT monitor since they have no phosphor. But it’s still the video card that dictate the data rate and the timing, and that’s why you can have a vertical sync interrupt even with a LCD connected.

I just wanted to put your attention at the right direction since you seem to lack some basic understanding of video systems; my reply was in no way a complete explanation.

Maybe this can help you… http://www.tweakguides.com/Graphics_7.html

Great link.

 

Quiz, it was seven paragraphs before you got to 'framebuffer,' and no mention of 'back buffering'. Get more familiar with those two and you probably will never have to worry about screen tearing again, as it takes either some really horrible code or really highend graphics for that to happen.

  Quizzical

Guide

Joined: 12/11/08
Posts: 13180

 
OP  1/14/13 3:23:41 PM#6
Originally posted by Loktofeit
Originally posted by Sandbox
Originally posted by Quizzical
Originally posted by Sandbox

If you have a CRT monitor, the timing is determind by the video source and not by the monitor. You have both horizontal and vertical sync pulses and blanking periods etc.

Most video cards are able to react on vertical sync interrupt signals and update/switch the framebuffer during this period.

Use verical sync signals and double buffers to avoid the tearing.

Framerate conversion generated stuttering, like 40 hz to 60 hz i mostly an issue if you have continious movements. Most games have variation in their generated framerate but that are handled by modern GPUs.

Back to your question, you have to meassure the syncpulses from the videoboard to get a correct answer.

As best as I can tell, OpenGL does not have any vertical sync capabilities built into the API.  It does use double-buffering by default, though.

I'm using an LCD monitor, not a CRT.  Actually two LCD monitors, but the red/blue flashing test found that when they get a new frame, they both get the framebuffer as it existed at exactly the same time.

And I do think I have a correct answer for my hardware.  It seems likely that my method could find the answer for a lot of other hardware, too, though I don't know.  I posted this largely because I thought it was interesting.

Even LCD monitors have frame rate specification, mostly due the bandwidth limitations. One difference is they don’t have to clear the screen like a CRT monitor since they have no phosphor. But it’s still the video card that dictate the data rate and the timing, and that’s why you can have a vertical sync interrupt even with a LCD connected.

I just wanted to put your attention at the right direction since you seem to lack some basic understanding of video systems; my reply was in no way a complete explanation.

Maybe this can help you… http://www.tweakguides.com/Graphics_7.html

Great link.

 

Quiz, it was seven paragraphs before you got to 'framebuffer,' and no mention of 'back buffering'. Get more familiar with those two and you probably will never have to worry about screen tearing again, as it takes either some really horrible code or really highend graphics for that to happen.

Screen tearing already isn't an issue.  I even went out of my way to try to cause it and couldn't.  I think that it's implicitly handled by video drivers.

JOGL uses double-buffering by default.  All rendering is done on the back buffer.  When a call to display() returns (which means that a frame in the back buffer is completed), it automatically swaps the front and back buffers.  (Or perhaps rather, the front left and back left buffers; OpenGL 4.2 has quad buffering.)  What seems to happen is that the video card periodically decides that it's time to send a frame to the monitor, and copies the contents of the front buffer elsewhere to send it to the monitor--and won't allow the front buffer to be written to during that time.

What I want to know is exactly when the video card will decide that it's time to grab the contents of the front buffer and send it to the monitor.  That should make it possible to have smoother animations.  The ideal solution, which likely isn't possible, would be for me to be able to be able to request that the next time it grabs the front buffer, it also calls System.nanoTime() and records the value of that for me to use however I want.  That would make things easy for me.

Absent that, I could do the testing as described in the original post to get a pretty good approximation.  The problem is that I have to stop rendering the game to do that testing.  If the average frame time on a given hardware configuration doesn't vary, then I could do a one time test that takes a couple of minutes to compute it, and then store that value.

Then I'd need the offset, which I could compute in a fraction of a second at a cost of making the game window flicker a bit (i.e., alternate between two colors very rapidly; the colors could be very close to each other to avoid being obnoxious) instead of rendering the game.  The offset would need to be refreshed periodically.  If I can get the average frame time to within a few nanoseconds, then refreshing the offset every few hours is sufficient.  Stopping to do that when there isn't anything important to render (e.g., when loading the game or switching characters) should work fine.

The problem is that the offset will drift each frame by however far off my average frame value is.  Multiply that by about 216,000 frames per hour and trying to keep the proper value to within about a millisecond precision means I'd better have the average value pretty accurately--and it better not change for a given hardware configuration.

-----

As for the link, that does give the basics of how monitors work.  The problem is that just knowing the monitor refresh rate is around 60 times per second isn't good enough for my purposes.

The link also seems to be very old.  I don't know if their description of the graphics pipeline was ever correct, but at the very least, it hasn't been for a long time.  Among other things, they're assuming fixed-function lighting.  Lighting calculations can be done in any of several pipeline stages, or even spread across multiple stages, but regardless of where they're done, they're not fixed-function anymore.

  Sandbox

Novice Member

Joined: 8/23/06
Posts: 309

1/14/13 3:59:06 PM#7

As I already said, it's the video cards refresh rate AND timing that matters. Not the refresh rate of the monitor.

Either you continue to bang your head against the wall, or find a "how to" describing how to enable vertical sync or similar signalling from you hardware.

Found this in a OpenGL wiki:

Use the WGL_EXT_swap_control extension to control swap interval. Check both the standard extensions string via glGetString?(GL_EXTENSIONS) and the WGL-specific extensions string via wglGetExtensionsStringARB() to verify that WGL_EXT_swap_control is actually present.

The extension provides the wglSwapIntervalEXT() function, which directly specifies the swap interval. wglSwapIntervalEXT(1) is used to enable vsync; wglSwapIntervalEXT(0) to disable vsync.

Another option is to find a card that supports what you need.

  Quizzical

Guide

Joined: 12/11/08
Posts: 13180

 
OP  1/14/13 6:53:30 PM#8
Originally posted by Sandbox

As I already said, it's the video cards refresh rate AND timing that matters. Not the refresh rate of the monitor.

Either you continue to bang your head against the wall, or find a "how to" describing how to enable vertical sync or similar signalling from you hardware.

Found this in a OpenGL wiki:

Use the WGL_EXT_swap_control extension to control swap interval. Check both the standard extensions string via glGetString?(GL_EXTENSIONS) and the WGL-specific extensions string via wglGetExtensionsStringARB() to verify that WGL_EXT_swap_control is actually present.

The extension provides the wglSwapIntervalEXT() function, which directly specifies the swap interval. wglSwapIntervalEXT(1) is used to enable vsync; wglSwapIntervalEXT(0) to disable vsync.

Another option is to find a card that supports what you need.

That controls when the front and back buffers are swapped.  The default functionality of JOGL works fine for me there.  But that's not what I'm after.  I want to know when the video card takes the front buffer and copies it elsewhere to send it to the monitor for display.

And as I've said repeatedly, I think I can measure exactly that in a convoluted way.

  Ridelynn

Elite Member

Joined: 12/19/10
Posts: 3323

1/14/13 9:18:09 PM#9

I think, there are probably more variables than you are taking into account.

Missing nanoseconds here and there when measuring frame rate response isn't all together unreasonable. There are things that happen other than your code (like the Windows scheduler) that can interrupt your process and throw off that clock by some small margin, that are completely external to your program.

For ~most~ purposes, you either render as fast as you can and just let the monitor show what it's able (and risk tearing), or you just enable VSYNC and let the driver take care of throttling the frame rate for you, and that's good enough.

For applications that require a higher degree of accuracy, your probably going to need to dig down a lot deeper than Java will let you, since your more or less stuck inside of the Java VM, and need more direct access to the underpinnings - and it may be that you can't get that with the way Windows architecture is laid out in the first place (I'm not entirely certain - to get that level of accuracy you may need to look at some embedded-type OS hooks or look toward modified/modifying a linux kernal).

  Ichmen

Apprentice Member

Joined: 4/15/06
Posts: 1234

hatred enriches.
life is a prison, death a release.

1/14/13 9:39:05 PM#10

im kinda curious on this my self as my lcd tends to be 59-60hz while i typically dont notice tearing or such issues (apart from GPU limitions i suffer) id love to know if buying a 1000000hz monitor is really any better then a 60hz

be nice to know if this refresh rate would boost the avoidance of lag from system hardware or if it would really matter all that much. 

 

but then again.. most of this stuff to beyond my tech knowledge :/

CPU: Intel Core i7 CPU 860 2.8GHz
Evga GeForce 670 FTW
Evga P55 SLI

<

  Quizzical

Guide

Joined: 12/11/08
Posts: 13180

 
OP  1/14/13 10:19:42 PM#11
Originally posted by Ridelynn

I think, there are probably more variables than you are taking into account.

Missing nanoseconds here and there when measuring frame rate response isn't all together unreasonable. There are things that happen other than your code (like the Windows scheduler) that can interrupt your process and throw off that clock by some small margin, that are completely external to your program.

For ~most~ purposes, you either render as fast as you can and just let the monitor show what it's able (and risk tearing), or you just enable VSYNC and let the driver take care of throttling the frame rate for you, and that's good enough.

For applications that require a higher degree of accuracy, your probably going to need to dig down a lot deeper than Java will let you, since your more or less stuck inside of the Java VM, and need more direct access to the underpinnings - and it may be that you can't get that with the way Windows architecture is laid out in the first place (I'm not entirely certain - to get that level of accuracy you may need to look at some embedded-type OS hooks or look toward modified/modifying a linux kernal).

Perhaps I should back up and say that this isn't something that I absolutely need to do for the game to work.  The game works fine without it, and there isn't any tearing.  But if a few days of work can make all animations visibly smoother and take several milliseconds off of the display latency on higher end hardware while having the vertical sync advantages of easing the load on hardware, then I'll do it.

I don't need to control when the video card will grab a frame to send to the monitor.  I only want to be able to predict it.  If it's based on regular intervals in whatever timer it uses (as is highly probable), and the timer it uses is the same one that Java exposes either with System.nanoTime() or System.currentTimeMillis(), then I can do exactly that.  If it uses some other timer that doesn't run at a rate very closely proportional to either of those, then it will just mean I spent a few hours tinkering with something that didn't work out.  Oh well.  It wouldn't be the first time.

I suppose the way to do it is to try to implement it and see if it works.  It's entirely possible that it will work on some systems and not others, in which case, it's easy enough to leave it as an option for the end user to turn on or off.

  Quizzical

Guide

Joined: 12/11/08
Posts: 13180

 
OP  1/14/13 10:22:23 PM#12
Originally posted by Ichmen

im kinda curious on this my self as my lcd tends to be 59-60hz while i typically dont notice tearing or such issues (apart from GPU limitions i suffer) id love to know if buying a 1000000hz monitor is really any better then a 60hz

be nice to know if this refresh rate would boost the avoidance of lag from system hardware or if it would really matter all that much. 

 

but then again.. most of this stuff to beyond my tech knowledge :/

A monitor with a 120 Hz refresh rate will tend to make animations look smoother and reduce your display latency by several milliseconds.  But it can really be the difference between animations that look fairly smooth and ones that look very smooth.  If the problem is that your system just can't compute frames fast enough, then it's going to be choppy no matter what you do for a monitor.

  grndzro

Advanced Member

Joined: 2/21/06
Posts: 1096

1/15/13 12:36:37 AM#13

Usually the refresh rate of a monitor is a slightly variable function of the hardware that is used in the monitor. Drivers have built in algorithms that adjust to the hardware tolerances in the monitors. So one 23 inch monitor might be at 59hz while another of the same kind could be at 61. It's hiden in the way drivers deal with the frequency tolerances. At least that's the way I understood it from CRT monitors.

In LCD monitors I'd say they are probably set up to much closer tolerances due to the fact that the LCD crystals don't really care what HZ they are at as long as it isn't higher than they are capable of. Digital systems probably have a clock crystal built in. No idea though.

From a programming perspective setting up a timing/refresh test set to the system clock could determin how close you are to 60 hz. But I'm not a programmer.

  syntax42

Elite Member

Joined: 3/30/07
Posts: 1092

1/15/13 7:41:58 AM#14

The poster above is fairly close to what I would guess.  Old television sets used the AC power waveform to set their scan rates.  Modern electronics may not do the same thing, but the function of the device builds on the flaws of its predecessors.  The problem was that the monitor and the video source had little real synchronization.  

 

I'm not a programmer, but i was reading the posts and had an idea.  Instead of trying to predict the frames, draw the next frame right after the monitor grabs the latest frame.  Wait to draw the next frame until the monitor grabs the latest one.  This way, you will produce one frame every time the monitor grabs a frame and your frames will be spaced perfectly apart.  This would require the use of the front and back buffers as mentioned in previous posts to ensure the monitor is only reading a frame which has been drawn completely.

 

Basically, your game state would be just under 16.7ms ahead of your monitor, assuming a perfect 60Hz refresh.  Every frame would be drawn 16.7ms after the previous, producing the smoothest possible animation for you.  This is only possible if you have access to the ability to detect when the monitor has grabbed the frame from the buffer.

 

Did all of that make sense?  Is it even possible with the programming language you are using?

  lizardbones

Elite Member

Joined: 6/11/08
Posts: 10430

I've become dependent upon spell check. My apologies for stupid grammatical errors.

1/15/13 8:19:02 AM#15

The issue isn't the monitor, unless something is wrong with it. It's probably the video card or cpu being too weak for the content being displayed. It's also possible for a video card to somehow get out of sync with a monitor's refresh rate, so that half the screen is one frame, and half the screen is another frame. There's often a setting in games that keeps the video card synced with the monitor. I've never used it, but I know it exists. Maybe try that.

Most HD televisions, even those suited to BlueRay HD run at 60hz. You get diminishing returns at refresh rates higher than 60hz. For instance, the difference between 15hz and 30hz is HUGE. You go from something that isn't watchable, to something you could actually watch. For instance, movie theaters have been running at 24hz since forever and are only recently trying out higher refresh rates. From 30hz to 60hz, you go from something that is watchable and even enjoyable to something that looks really smooth with any post processing on the video being displayed and works well with interactive things like video games. From 60hz to 120hz you get a slight improvement that many people can't even see because they are humans and not bug eyed aliens. Even BlueRay HD benefits very little from having a 120hz refresh rate. For instance, they have built televisions that are capable of running at 600hz, but consumers don't need them. The only real use of 120hz televisions now is having screens that are slightly smoother for a good bit more money, or displaying content in 3D by displaying two different videos at 60hz each.

I have read a couple posts, but I haven't read the OP, so if this has nothing to do with the OP, my apologies.

** Lordy, lordy. I just read the OP. My post has nothing to do with it. I'm also going to posit that the OP is too smart to be posting on these forums, and also has too much time to just experiment. I don't know what they look like, but I imagine them bald, face hidden in darkness, with a mechanical hand, petting a cat that looks like a tiny tiger, with green eyes. They have already laid out their plans, and they are just waiting...

For every large, complex problem, there is a simple, clear solution that also happens to be absolutely wrong.

  Quizzical

Guide

Joined: 12/11/08
Posts: 13180

 
OP  1/15/13 10:27:54 AM#16
Originally posted by syntax42

I'm not a programmer, but i was reading the posts and had an idea.  Instead of trying to predict the frames, draw the next frame right after the monitor grabs the latest frame.  Wait to draw the next frame until the monitor grabs the latest one.  This way, you will produce one frame every time the monitor grabs a frame and your frames will be spaced perfectly apart.  This would require the use of the front and back buffers as mentioned in previous posts to ensure the monitor is only reading a frame which has been drawn completely.

 

Basically, your game state would be just under 16.7ms ahead of your monitor, assuming a perfect 60Hz refresh.  Every frame would be drawn 16.7ms after the previous, producing the smoothest possible animation for you.  This is only possible if you have access to the ability to detect when the monitor has grabbed the frame from the buffer.

The problem is that I have no way to directly find out when a frame is grabbed and sent to the monitor.  The way that I measure it indirectly is by spamming a bunch of junk frames that are a solid color, measuring how long each takes, and looking for outliers that take much longer than most.  A long frame (in this case, over 0.4 ms) usually but does not always correspond to when a frame was sent to the monitor.  Continuing the test for 100 ms or so and looking for a set of several long frames spaced about 16-17 ms apart is able to pin it down.

The problem is that having the monitor go blank so I can spam junk frames for 100 ms in the middle of a game is rather disruptive to gameplay.  You can do something like that at loading screens, but I don't have any loading screens.  Loading a game initially or switching characters (my idea of fast travel:  in-game characters can't warp, but you can switch which character you control so that you effectively warp to a different area of the world) means that there will be a brief period when a lot of the stuff that needs to be drawn isn't loaded.  Having the screen go blank for 100 ms or so when that happens would be perfectly acceptable.

But that means that I can only sporadically find out when a frame is sent to the monitor.  I can't find out every frame, or even once every thousand frames.  I expect it to be fairly rare for players to go more than about 200,000 frames without giving me a chance to check when frames are sent.  (One full day/night cycle is 1 real-life hour, and being outside of town at night kills you.  So if it's getting dark, maybe you should switch characters to somewhere where it is morning.)

  lizardbones

Elite Member

Joined: 6/11/08
Posts: 10430

I've become dependent upon spell check. My apologies for stupid grammatical errors.

1/15/13 11:22:44 AM#17

Is your game a full screen Java application?

This site (http://www.java-gaming.org/topics/why-java-games-look-choppy-vertical-retrace/14696/view.html) references a method to get smooth animations, without having to predict when a frame is being written. It apparently doesn't apply to Java 2D, and from other sites I was reading can give inconsistent performance depending on whether you're running Windows or Linux. It works under Windows, but only works under certain versions of Java under Linux.

The relevant quote from the page:


"The fix is easy for anyone writing a fullscreen Java application; applications that use the FlipBufferStrategy get this for free. When that buffer strategy copies its contents to the screen from the back buffer, it specifically waits for the vertical blank interface, and thus avoids tearing completely.

The fix is not as easy for typical windowed (non-fullscreen) applications, because there is currently no way to tell Java to wait for this interval, and there is no way for your code to know when it is a good time to go ahead with the copy. We hope to address this in a future release (I just filed a bug on it last week!), but in the meantime there is no way to get this behavior."




There are two blog posts referenced with more detailed information.
http://weblogs.java.net/blog/chet/archive/2006/02/make_your_anima.html
http://today.java.net/pub/a/today/2006/02/23/smooth-moves-solutions.html#handling-vertical-retrace.html

The information is pretty old though...so it might not be helpful.

For every large, complex problem, there is a simple, clear solution that also happens to be absolutely wrong.

  Ridelynn

Elite Member

Joined: 12/19/10
Posts: 3323

1/15/13 2:06:48 PM#18

A better question may be to take a step back and ask:

Why are you trying to write a game in Java in the first place? There are a lot of drawbacks to picking Java in particular to program with.

  Quizzical

Guide

Joined: 12/11/08
Posts: 13180

 
OP  1/15/13 2:14:22 PM#19
Originally posted by Ridelynn

A better question may be to take a step back and ask:

Why are you trying to write a game in Java in the first place? There are a lot of drawbacks to picking Java in particular to program with.

Because I didn't expect to get very far, and then didn't want to scrap it and start over.

Exactly what drawbacks should I be warned about?  Java and OpenGL seem to have all of the capabilities that I need, though I haven't tested Java's sound and network capabilities to see just how robust they are.  I'm not a computer programmer by training, so I really don't know the pros and cons of this language versus that one.

  lizardbones

Elite Member

Joined: 6/11/08
Posts: 10430

I've become dependent upon spell check. My apologies for stupid grammatical errors.

1/15/13 2:19:15 PM#20


Originally posted by Quizzical

Originally posted by Ridelynn A better question may be to take a step back and ask: Why are you trying to write a game in Java in the first place? There are a lot of drawbacks to picking Java in particular to program with.
Because I didn't expect to get very far, and then didn't want to scrap it and start over.

Exactly what drawbacks should I be warned about?  Java and OpenGL seem to have all of the capabilities that I need, though I haven't tested Java's sound and network capabilities to see just how robust they are.  I'm not a computer programmer by training, so I really don't know the pros and cons of this language versus that one.




Was it a shock to end up with a functional game, or was it a nice surprise?

For every large, complex problem, there is a simple, clear solution that also happens to be absolutely wrong.

2 Pages 1 2 » Search