Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add platform polyfills for retrieving window.deviceScalingRatio #582

Merged

Conversation

Drigax
Copy link
Contributor

@Drigax Drigax commented Jan 22, 2021

This PR modifies the Window polyfill contract to retain a reference to the native window implementation, and creates platform implementations of retreiving the DPI scaling of that window.

Dependent on Babylon.js pull request: BabylonJS/Babylon.js#9892 in order to enable auto-scaling on engine creation.

Fixes #482 #620

Drigax and others added 19 commits December 17, 2020 00:43
…/BabylonNative into add-engine-hardware-scaling-level
…/BabylonNative into add-engine-hardware-scaling-level
Co-authored-by: Ryan Tremblay <ryantrem@msn.com>
…d windows window header to CMAKElists, update applications to use new contract
Core/Graphics/Source/Graphics.cpp Outdated Show resolved Hide resolved
Core/Graphics/Source/Graphics.cpp Outdated Show resolved Hide resolved
Core/Graphics/Source/Graphics.cpp Outdated Show resolved Hide resolved
Core/Graphics/Source/Graphics.cpp Outdated Show resolved Hide resolved
Polyfills/Window/Source/Window.cpp Outdated Show resolved Hide resolved
void* windowPtr = (__bridge void*)engineView;

graphics = Babylon::Graphics::CreateGraphics(windowPtr, static_cast<size_t>(600), static_cast<size_t>(400));
GraphicsConfiguration graphicsConfig = GraphicsConfiguration();
graphicsConfig.windowPtr = engineView;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this compile? Isn't graphicsConfig.windowPtr of type MTKView*?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're declaring the interface EngineView to be an MTKView via L18

Comment on lines +61 to +62
template<typename WindowT>
WindowT GetNativeWindow();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, this is the change that tries to eliminate the need to compile with the objective C++ flag, is that right? It seems very awkward though, and like we have a weird mix of known and sort of unknown types in the API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that if we want this function as a member of GraphicsImpl we either A) go back to using void*, B) use the platform type in this header, causing compilation issues with our consumers if the headers arent c++, or c) use some templating to obscure the type in the header.

The alternative is to make it some odd utility function that uses GraphicsImpl? C++ makes these types of situations difficult.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it's a little awkward, but (in my opinion) much less so than having a bunch of C++ libraries that have to be compiled as Objective C++ just so that they can find a type that they don't actually use in C++. The reason for templating this instead of forward-declaring MTKView is because Apple defines MTKView as an interface, which didn't seem to play nicely with our attempts to forward-declare it in C++. Because this is an internal contract, not a proper outward-facing API, I don't think it's too big a deal for it to have this small degree of awkwardness.

If it's bothersome, though, I can think of two other option to do this cleanly, though the first is (in my opinion) even more awkward: have a special platform-specific struct defined just like the config struct, the only purpose of which is to contain an MTKView*, then forward-declare that and use it as the return type. This is awkward because it entails having an entire type which has to be implemented per-platform just for the purpose of avoiding a templated function.

The second approach would be to simply move this function definition to a platform-specific header, using our CMake practices to deliver the right header to the right consumer. This is probably my favorite of the three, but it's still a little awkward because you'd need to take it out of the class, making it GetNativeWindowFromGraphicsImpl(GraphicsImpl&) or something, which could get odd. Bottom line, I think all three of these approaches are equally viable and equally awkward, so I don't really have a strong personal preference among them.


namespace Babylon
{
class Graphics::Impl : public GraphicsImpl { };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GraphicsImpl.h is now no longer included by Graphics.h,
So we declare Graphics::Impl in Graphics.h, then define it as our internal type in the .cpp where we use it.

The idea was to remove it from the public contract.

Copy link
Contributor Author

@Drigax Drigax Mar 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until I realized that we also needed to remove references to our platform types for consumers of the private contract as well, so the intent of this change was wrong. I don't really think its a bad change, however.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change also allows Graphics::Impl to become a private class, right? It's public now, though GitHub won't let me put a comment directly on it in the header because it's too far away from a changed line.

@@ -126,7 +131,11 @@ extern "C"
{
ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
g_runtime->Dispatch([window, width = static_cast<size_t>(width), height = static_cast<size_t>(height)](auto env) {
g_graphics->UpdateWindow<void*>(window);
GraphicsConfiguration graphicsConfig = GraphicsConfiguration();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before. You might consider giving GraphicsConfiguration a constructor that takes arguments, though, so you don't have to write out a block of code every time you make one of these.

Copy link
Contributor Author

@Drigax Drigax Mar 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured using the default constructor and populating the fields independently in our sample playground gives us the flexibility to expand the GraphicsConfiguration object without needing to update existing code that populates this struct. I considered using a list initializer as well, and using a constructor with optional parameters, however we're still constrained by the ordering of the members in the struct, but maybe i'm playing it up to be more important than it is...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggestion to have a constructor take arguments isn't really more than a nit, so it's not that important. That said, you can still choose to not use the constructor if it doesn't fit your use case, and you can have multiple constructors if you have several typical use cases. In this case, since you're writing the same four or five lines of code multiple times in multiple places, this initialization scenario seems common enough to warrant a constructor (which, if the struct is later expanded with other members, could just leave those blank if it wants to since they by definition won't pertain to this usage). As I said, though, it's a nit, so just a judgement call. The main thing this comment was to document was the same thing as the long one: the initialization code.

Apps/Playground/UWP/App.cpp Outdated Show resolved Hide resolved
Apps/Playground/Win32/App.cpp Outdated Show resolved Hide resolved
Apps/Playground/X11/App.cpp Outdated Show resolved Hide resolved
Plugins/NativeCapture/CMakeLists.txt Outdated Show resolved Hide resolved
Plugins/NativeEngine/CMakeLists.txt Outdated Show resolved Hide resolved
Polyfills/Window/Source/Window.cpp Outdated Show resolved Hide resolved
Polyfills/Window/Source/Window.h Outdated Show resolved Hide resolved
@Drigax Drigax merged commit 8371b79 into BabylonJS:master Mar 31, 2021
@Drigax Drigax deleted the add-window-device-scaling-ratio-polyfill branch March 31, 2021 18:34
@ryantrem
Copy link
Member

ryantrem commented Apr 1, 2021

Hey @Drigax - since this has Babylon Native API breaking changes, are you planning to update Babylon React Native? There are some other PRs out with updates to both Babylon Native and Babylon React Native, and I think these are blocked until Babylon React Native is updated to deal with the API changes.

@Drigax
Copy link
Contributor Author

Drigax commented Apr 1, 2021

Hey @Drigax - since this has Babylon Native API breaking changes, are you planning to update Babylon React Native? There are some other PRs out with updates to both Babylon Native and Babylon React Native, and I think these are blocked until Babylon React Native is updated to deal with the API changes.

I see, I don't believe the PRs are blocked, since they're updating the submodule to a commit prior to mine, however I have the changes staging here, and will have a PR open shortly:

https://github.com/Drigax/BabylonReactNative/tree/update-graphics-contract

@@ -6,19 +6,18 @@

namespace Babylon
{
struct GraphicsConfiguration;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This isn't where I was thinking the forward declaration for this would go; I was assuming you'd just include GraphicsPlatform.h here because (I think) the general expectation is that consumers of this file will need GraphicsPlatform.h. The forward declaration would then just be for GraphicsImpl.h, which is (I think) the only file where we explicitly need to avoid the platform types.

@@ -0,0 +1,13 @@
#pragma once

#include <Babylon/Graphics.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be missing something, but this relationship seems backwards. Should Graphics.h include GraphicsImpl.h, not the other way around? I'm thinking that consumers should be including Graphics.h (which, will then give them GraphicsPlatform.h as an implementation detail); what's the reasoning for doing it this other way?

@@ -6,19 +6,18 @@

namespace Babylon
{
struct GraphicsConfiguration;

class Graphics
{
public:
class Impl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this type can be private now.

#include <Babylon/GraphicsPlatform.h>
#include "../GraphicsImpl.h"

constexpr float MILLIMETERS_TO_INCHES = 0.03937;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that number on the right is a double, not a float, but I could be wrong as I'm kind of surprised this compiled. Should this number use the f suffix?

@@ -3,6 +3,7 @@
#include <arcana/containers/ticketed_collection.h>

#include <Babylon/JsRuntime.h>
#include <Babylon/Graphics.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Graphics.h? I didn't think this file needed to know about the Graphics contract, just the GraphicsImpl and GraphicsConfigration contracts. Do we ever deal with Graphics directly here?

#include <basen.hpp>
#include <chrono>
#include <iterator>
#include "Window.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conventionally, this goes at the top. What was the reasoning for moving this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Graphics contract changes Support DPI
7 participants