CSS upscaling / force resolution

126 views Asked by At

I'm working on a webgame and for performance reasons I'd like to render the UI at a certain resolution (lets say 640x480) and scale it up (just like you'd do with an image). Some transformations and background effects require quite some reflows/repaints, and for the experience its not really important to render these at a 4K resolution.

But I noticed that when I for example use scale(2) on a parent container, fonts, shadows and background gradiants are just rendered at a resolution x2 instead of rendering them at x1 and scale its result x2 (like im able to do with the contents of an canvas). I tried rendering it in an iframe and scaling this iframe x2, but still this results in the UI being rendered at x2 resolution.

Does anyone know of a way to achieve this?

EDIT: working example

<html>
    <head>
        <meta name="viewport" content="width=320px, height=240px, initial-scale=1, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                background: black;
                width: 100vw;
                height: 100vh;
            }
            #iframed {
                width: 320px;
                height: 200px;
            }
            #scaled-game {
                text-rendering: optimizeSpeed;
                font-smooth: never;
                backface-visibility: hidden;
                will-change: transform;
                position: absolute;
                left: 50%;
                top: 50%;
                transform: translateX(-50%) translateY(-50%) scale(2);
            }
        </style>
    </head>

    <body>
        <div id="scaled-game">
            <iframe
                id="iframed"
                scrolling="no"
                frameborder="no"
                allow="autoplay"
                width="320px"
                height="200px"
                allowfullscreen
                srcdoc='
                    <html>
                        <style>
                            body {
                                background: black;
                                text-rendering: optimizeSpeed;
                                font-smooth: never;
                                backface-visibility: hidden;
                            }
                            #game {
                                position: absolute;
                                will-change: background-position;
                                min-width: 320px;
                                width: 320px;
                                max-width: 320px;
                                min-height: 200px;
                                height: 200px;
                                max-height: 200px;
                                border: none;
                                filter: drop-shadow(0px 0px 4px green) drop-shadow(0px 0px 6px darkgreen);
                            }
                            #gui {
                                position: absolute;
                            }
                            #txt {
                                top: 0;
                                transform: translate(0%, 50%);
                                font-size: 25px;
                                text-align: center;
                                color: white;
                                text-shadow: 0px 4px 3px rgba(0,0,0,0.4), 0px 8px 13px rgba(0,0,0,0.1), 0px 18px 23px rgba(0,0,0,0.1);
                            }
                            #game:before {
                              position: absolute;
                              top: 0;
                              left: 0;
                              width: 100%;
                              height: 100%;
                              content: "";
                              transform: translateZ(0);
                              transform: translateZ(0);
                              transform-origin: 50% 50% 0;
                              animation-name: sideupscroll;
                              animation-duration: 80s;
                              animation-timing-function: linear;
                              animation-iteration-count: infinite;
                              background: url("http://i.imgur.com/wNna7D3.png") repeat fixed 0 0 indigo;
                              animation-fill-mode: both;
                              border: 2px solid white;
                              border-radius: 7px;
                            }
                            @keyframes sideupscroll {
                              0% {
                                background-position: 0 0;
                              }
                              50% {
                                background-position: -50% -100%;
                              }
                              100% {
                                background-position: -100% -200%;
                              }
                            }
                        </style>
                        <body>
                            <div id="game">
                            </div>
                            <div id="gui">
                                <p id="txt">TEXT & SHADOWS KEEP BEING SHARP</p>
                            </div>
                        </body>
                    </html>
                '>
            </iframe>
        </div>
    </body>
</html>

1

There are 1 answers

0
shuunenkinenbi On

You achieved what you wanted to achieve: The upscaled version does indeed requires less memory of the GPU. Things like text, border, shadow etc. scale without loss of quality. They're essentially vectorized. What does get blurry, however, are upscaled images (and background images).

I did something similar with a semitransparent black overlay. Instead of creating a 100%/100% div, i created a 1%/1% div and scaled it up to fill the entire screen (using transforms). It worked - and the saved memory was measurable in devtools.