text:
The challenge is finding the right solution: Haydn Furlonge
For Brunei National Petroleum Company CEO Haydn Furlonge, moving to Brunei Darussalam for a new opportunity and experience was a bold step, aiming to lend his expertise to the oil and gas industry.
Haydn Furlonge
CEO, Brunei National Petroleum Company
Words - Stephanie McDonald
Taking a leap of faith into the unknown can be a daunting prospect but with great risks come great rewards and Haydn Furlonge, CEO of Brunei National Petroleum Company (BNPC), has no regrets about the risks that he's taken.
This includes taking an opportunity to move to Brunei Darussalam, a country he knew little about before stepping into his current role. "It was an opening that was presented to me.
I'm not sure why it came along but it did, and I took a bold step with the support of my family," he says. Haydn says he is grateful for the opportunity provided by the Government of His Majesty the Sultan and Yang Di-Pertuan of Brunei Darussalam. "So far, so good. I don't have any regrets about these leaps of faith I have taken."
"I don't have any regrets about these leaps of faith I have taken."
While Haydn was attracted to the role because he wanted to experience a different business culture, with Brunei being on the opposite side of the world to Trinidad and Tobago – where he grew up – the challenges of the oil and gas industry also appealed to him.
"When I joined the industry in Trinidad and Tobago, it was a very difficult time for the sector in general," he says. "That was more than 20 years ago and the challenge has been how to develop a strategy to survive in the short-term but also be ready for new opportunities."
Haydn has had a roundabout path into the oil and gas industry. He postponed working in the sector after completing a degree in chemical and process engineering to undertake research at The University of the West Indies and Imperial College London.
During his time with BNPC, he has enjoyed the fact that it is a constantly changing and dynamic industry. "It goes through cycles but there is also a lot of volatility in the market, and therefore significant risk in the business. Dealing with all of these variations and dynamics makes the job very interesting," Haydn says.
For Haydn, one of the key facets of the industry is having good relationships – he believes they are vital because no single person can build an entire energy value chain. This means always working with other entities, communities and government agencies.
"I think the dynamics and the relationships are the most important aspects," he says. "There is excitement in finding the right solution to make everything work. At the end of the day, it takes a long time, because the nature of it is that you spend several years developing a business and the benefits only present themselves well into the future."
Brunei Darussalam has a long history in the energy sector, and the industry has played a critical role in the country's economy, contributing to more than 60% of its GDP. The South-East Asian nation is looking to continue capitalising on this and making the most of its oil and gas fields, while also boosting local content.
"I have seen the energy sector contribute to economic growth and I believe in the potential for another wave of development in Brunei," Haydn says. "I think what is important for us is to maximise value from that growth and be able to realise not just the monetary aspect but also the added value in terms of job creation, skills development and local businesses."
Those principles are helping to drive BNPC, a varied organisation that is involved in every segment of the energy value chain, including exploration, development, production involving deep- and shallow-water projects, petrochemicals, marketing and trading, and energy services. Given that the company grew very quickly, Haydn says he realised the way it worked had to change.
"The company is very diversified – we actually have 12 subsidiaries and joint venture companies, so managing all of these became quite challenging with a relatively small staff base. But with strong teamwork and dedication, we are able to overcome those challenges," Haydn says.
The company seized the chance to consolidate, and to change the structure and governance model. Changes included focusing on new areas and aligning the organisation into an integrated business, which he believes will maximise returns and help manage the risks of the oil and gas business by distributing risk across the full chain.
"We now work in a much more agile manner, meaning we control dynamics very quickly; we can kickstart projects and initiatives with multidisciplinary teams and, once these are mature, we pass them on to the respective lines," he says.
BNPC is now turning its focus to boosting the performance of its existing assets. "Our methanol production plant and tanker businesses are back on track; our marketing and trading portfolio has increased, our fabrication yard has new activity, and we won a new offshore services contract with our partners," Haydn explains.
"We also acquired new interest in a block in Brunei and are fast-tracking this development to bring the molecules to market." The company is also looking to explore and develop available hydrocarbon resources in Brunei with existing international oil and gas companies, as well as seeking new players to work with – such as Posco International, with which it signed a memorandum of understanding in November 2018 – to help develop a full gas value chain business.
Further, it is actively pursuing business in the services sector and is forming partnerships to provide services in drilling, decommissioning, EPC, rotating equipment, maintenance and repair, and renewable energy – the two latter activities with TNB REMACO and TNB Energy Services, wholly owned subsidiaries of Tenaga Nasional Berhad (the largest electric utility company in Malaysia and largest power company listed in South-East Asia).
"For us, it is about growth for the organisation but also about maximising in-country value – local job creation and local business development. This is going to be one of the key focuses for us going forward," Haydn says.
"Brunei is at the doorstep of the highest demand growth market in the world."
The industry has been growing very quickly within a short period, so it
is an extremely exciting time."
Haydn describes his leadership style as being driven by transformation and improving efficiency and decision-making, which he says takes a collaborative effort – bringing everyone to the table and allowing different views to be heard.
"The decision, at the end of the day, will have a lot more buy-in that way and everyone will be more motivated for its implementation," he says. "Building competency is also absolutely critical. One of the things we have done is put the organisation and our staff on a fast track to competency development, and succession planning for future leaders."
Haydn's belief in the importance of teamwork extends to how business is conducted – the nature of the oil and gas industry is such that it operates as a chain of activities, with everyone along that chain playing a key role.


Four years ago she lost her childhood sweetheart the second time.
Jamie West has returned home to Heart Valley and opened her own investigating business so she can help her mother who's been stricken with a debilitating disease. Though she grew up in Heart Valley, the picturesque little tourist town at the foot of the Teton Mountains is the last place Jamie wants to be. There are too many memories of Cole McDaniel here, the boy who was her first and only love, the boy who left home at eighteen and broke her heart, the boy who by age twenty-three was dead.
But when a single mom asks Jamie to find her missing daughter, she becomes drawn into a case that not only dredges up old, painful memories she'd rather forget, but is about to give her the shock of her life and bring someone new into it.
Can love conquer even death? Jamie is about to find out.
From bestselling author Linsey Lanier, Cole is the second book in the Heart Valley Romance series, a sweet romance series set in Heart Valley, Wyoming. The first five books in this series will feature the McDaniel family, owners of the McDaniel Resort Ranch, whose ancestors founded the town of Heart Valley near the Grand Teton Mountains back in pioneer days.


text:
Resources for Arbitrators
Tables of Decisions in ICSID Cases
Investment Mediation Insights: The Legal Framework on Investment Mediation—Quo Vadis?
ICSID's Investment Mediation Insights webinar series provides practical insights on the growing field of international investment mediation.
Episode one in the series took stock of how States have integrated investment mediation into the dispute resolution clauses of bilateral investment treaties, free trade agreements, and dispute settlement provisions in model treaties. We also reviewed the Energy Charter Secretariat's Model Instrument on Investment Dispute Management, which sets out policy options for a domestic legal framework to support effective investment dispute management, including through negotiation and mediation.
Topics Discussed:
How is mediation featured as a dispute settlement option in investment treaties? What are common approaches to doing so?
What are aspects policymakers may wish to keep in mind when drafting a mediation provision in an investment treaty?
What tools does the ECT Model Instrument on Management of Investment Disputes highlight for States to consider?
What domestic or international legal frameworks create 'enabling environments' for mediation of investment disputes? What trends are apparent and what is still needed at the domestic level?
Speakers:
Alejandro Carballo-Leyda: Alejandro is the General Counsel of the International Energy Charter and heads its Conflict Resolution Centre, which provides good offices and mediation support. From December 2020 to mid-September 2021, he was also the acting Deputy Secretary-General. He coordinated the Guide on Investment Mediation (2016), the Model Instrument on Management of Investment Disputes (2018) and the first training for investment mediators. Currently, he supports several countries in developing their internal instrument on preventing/managing investment disputes and is working on a joint research paper with the World Bank on investment dispute prevention in the energy sector. Alejandro also teaches foreign investment law at Paris 1 Panthéon-Sorbonne.
Anna Holloway: Anna (LLB(Hons)/BSc (University of Otago '03), LLM (HLS '07)) is a Legal Counsel at ICSID, where she assists arbitral tribunals and ad hoc committees, and contributes to ICSID's institutional projects, in particular ICSID's rules amendment process and the drafting of ICSID's mediation rules. Anna has led the Centre's extensive research on existing dispute resolution clauses in bilateral investment treaties, free trade agreements, and dispute settlement provisions in model treaties, analyzing the full range of approaches to integrating mediation in existing investment treaties. Prior to joining ICSID, Ms. Holloway was counsel in WilmerHale's international arbitration group (in London and DC) for 9 years. She began her legal career in New Zealand, first as a judge's clerk at the New Zealand Supreme Court, and then practicing as a barrister (2004 – 2006).
Frauke Nitschke: Frauke is a senior counsel at ICSID and serves as the team lead for one of the Centre's case management teams. Frauke further leads ICSID's investor-State mediation activities, including the development of the ICSID Mediation Rules, amendments to ICSID's conciliation frameworks, and ICSID's recent Background Paper on Investment Mediation. Frauke has developed and conducted investor-State capacity-building workshops and trainings for mediators and government officials, and led the Centre's contributions on mediation to the United Nations Commission on Trade and Law (UNCITRAL) Working Group III on investor-State dispute settlement reform. Frauke is an accredited mediator and admitted to practice law in New York and Washington, D.C. Frauke holds law degrees from the Freie Universität Berlin and Georgetown University Law Center (LL.M.), and a Master's degree in Organizational Psychology from the FU Hagen.

redpajama_set_name: RedPajamaCommonCrawl


1. WE GENERALLY RESTOCK ON MOST ITEMS WITHIN AROUND 2 WEEKS.
2. NEED FURTHER, MORE SPECIFIC INFORMATION ON RESTOCKING FOR A PARTICULAR ITEM?
1. PLEASE NOTE THAT WHILST WE WILL ENDEAVOR TO CANCEL OR CHANGE AN ORDER, WE CANNOT GUARANTEE THAT THESE CHANGES WILL TAKE PLACE IF THE ORDER HAS ALREADY PROCESSED.
1. IF YOU HAVE RECEIVED ONE OF THE ABOVE EMAILS IT MEANS THAT ALL OR PART OF YOUR ORDER IS CURRENTLY OUT OF STOCK. WE DO APOLOGIES FOR THE INCONVENIENCE.
WE TRANSIT YOUR ITEMS OR GIFTS TO "S.F EXPRESS", IF YOU ARE CHECKING YOUR SHIPMENT, YOU MAY CLICK HERE TO CHECK WITH YOUR TRACKING NUMBER GIVEN BY "S.F. EXPRESS"
WE OFFER NEXT WORKING DAY DELIVERY TO MACAO. IF YOU HAVE SELECTED THIS OPTION, YOUR ORDER WILL BE DELIVERED ON THE NEXT WORKING DAY AFTER YOU PLACED YOUR ORDER. IF YOUR ORDER IS PLACED ON THE WEEKEND OR AFTER 4.30 PM ON A FRIDAY IT WILL BE DELIVERED ON THE NEXT TUESDAY. IF THE ORDER IS PLACED ON A BANK HOLIDAY IT WILL BE DELIVERED ON THE NEXT WORKING DAY FOLLOWING THE FIRST WORKING DAY AFTER THE HOLIDAY.
WE ENDEAVOR TO ANSWER EMAIL QUERIES WITHIN 24 HOURS DURING WORKING HOURS.
NO.16 AVENIDA DO INFANTE D.HENRIQUE ED KAM LOI 2/K MACAO.


Here is another post of food adventures and this time round in Serangoon Estate. There are more upcoming cafes in the quiet area of Serangoon Estate which are not so accessible unless you have a car.
I have been wanting to try the famous rootbeer cake of Wimbly Lu Chocolates and here you find me in the Jalan Riang Estate!
You can take bus 107, 147, 853 from Serangoon Station bus stop and alight one stop later or you can walk one bus stop down from NEX mall.
Before trying the desserts of what Wimbly Lu is serving, I decided to venture around the restaurants in Jalan Riang to have a fulfilling dinner. They have a few restaurants along the same row as Wimbly Lu. One of them was 'The Cajun Kings' - serving crabs and lobsters and their way of eating those seafood is using a hammer and not any other types of cutleries! I shall go try it one day! Another restaurant I saw there was 'Siam Society' - I guess everyone should know it's Thai Food judging by the name of the restaurant. The other restaurant further down the row was Rokeby Bistro Cafe, which was an Australian Bistro and this restaurant was the most crowded of all so I decided to give it a try. I'm lucky because I managed to get the last table for 2 without making any reservation in advance.
The interior of the restaurant was quite cozy and they do not have many items on the menu.They have 2 items which caught my attention - which was the carbonara and chilli mussels. I had a hard time choosing and finally decided on the carbonara which is Da Bomb! I had also ordered a cappuccino to try too and oh boy, it did not disappoint me!
The waiting time for the drinks/food were fast too.
I managed to eat half of the pasta only as I'm not really a person who eat creamy pasta as I prefer tomato based pasta more. Thanks to the colleague who helped me to finish it. We spent around $23 per pax for dinner here and I find the prices quite reasonable. I intend to go there again in future to try the chilli mussels with bread.
After dinner, we wasted no time to head over to Wimbly Lu Chocolate cafe which was just a few shops away down the row.
We were considered lucky that we managed to get a table at 8pm.
Doesn't this look yummy but fattening though?
I had initially wanted to order rootbeer cake, waffles, rocky road & creme brulee but I was too full so I only settled for rootbeer cake (S$6) and chamomile tea ($5). The colleague ordered their famous waffle with chocolate ice-cream ($8.50).
The service was fast too.
The cafe was overcrowded with long queue by the time we left. If you want to try out this cafe, do try to go early.


text:
Respawn Confirms Development Of 'Titanfall 2'
The sequel is already in development.
Respawn Confirms Development Of 'Titanfall 2' : Read more
dstarr3
Because Titanfall was such a rousing success, especially after its first week after launch.
Nossy
I would've bought it if it had a single player campaign.
gggplaya
Maybe they'll compress the audio this time for PC users, now that practically everyone is using a SSD with lower capacity.
ohim
Success or no success.. am i the only one who hates this 1-2 year release date of another successor ? Are we getting like the phone industry where there`s a new model at less than 1 year a part ?
surphninja
Franchises are fine, but there needs to be a fair amount of time in between releases, especially if there's DLC. The worst thing about call of duty is the new game every year, so you're always having to buy a new game or new DLC, and there's ever any time to just enjoy the game without being expected to shell out more dough.
"...simply load up the Origin client..."
That part of the sentence sent a chill up my spine and made me cringe. It would be nice to play EA games on pc, but it's not worth downloading the Origin client.
ubercake
I bought Titanfall for PC when it came out and didn't play it all that much because most of my time on PC gaming is with either BF4 or Rocksmith 2014. When I first played it, I thought it was pretty good and a fresh change from the standard shooter, but was more concerned with getting my unlocks in BF4.
Flash forward to last month...
The deluxe edition (has all of the DLC/expansions) went on sale on Games with Gold on the Xbox One last month for $12.50 and I bought it to see how it played on the Xbox One compared to the PC version (I have a 3930K and GTX980 so the graphics are great on PC).
I have never like playing shooters let alone multi-player shooters on a console because I don't have my Kb/Mouse combo (I couldn't stand playing BF Hardline Beta or COD Ghosts on the console at all), but this game somehow makes a shooter fun and competitive for anyone with the controller on a console. The graphics and surround sound are also great on the Xbox One (of course they're better on the PC, but comparatively impressive on the Xbox One).
I haven't been too impressed with these "next-gen" console games in general, but I will say Titanfall on the Xbox One has become one of my favorite multi-player shooters and games ever.
I'm definitely looking forward to part deux and will be playing that game on the console.
Never4Nothing
Titanfall is a fun game, but the decision to use a half @ss aimbot known as a "Smart Pistol" was a terrible decision. "Gamers HATE aimbot cheaters so let's just include one in our game so gamers can hate it right away!" I hope they listen to the gaming community on the next version.
Never4Nothing :
At first, I thought it would be like an aimbot-enabled gun too. After playing the game quite a bit, I now don't consider the smart pistol a problem only because it takes a while to lock on to other players It is really hard to be competitive in a 'Pilot Hunter' match (think team deathmatch if your not familiar with this game mode) using the smart pistol against decent players because of the slower lock-on. It does lock on to AI grunts and spectres quickly so it gives even beginning players a chance to contribute to their team. The smart pistol is slow to lock on to other players even with the 'enhanced aiming' tactic chosen so there is definitely a disadvantage to using the smart pistol over any firearm you manually aim.
On the other side of the coin, if you're not very good with your aim on a console's controller, you can still have a decent amount of fun using it by picking up the grunts and spectres for your team as well as the occasional player who's not paying attention.
Ubercake. I can understand your assessment of the Smart Pistol for the "Noob" console players who obviously is not a Gamer and wants an easy gun to get kills with, but that just leads to my point. It ruins the game when you have a bunch of players using auto-targeting weapons on small maps. Auto-targeting on PC game is NOT accepted by the gaming community. I know many people who hate Titanfall because of the Smart Pistol, it's a shame because it is a great game and deserve more recognition.
ftw2
I enjoyed the game for PC. had a lot of fun. Sure bf4 is better overall and has way more content, but I wasn't dissappointed by titanfall. They play a lot differently.
The smart pistol is fine. It's no match for most of the other weapons in a head to head encounter.
agentbb007
I agree with Ubercake I actually like the smart pistol because my aim isn't super human so it allows me to actually get some kills sometimes (aka have fun).
road-rash
Well, It has been such a rousing success [/Sarcasm] that Origin is now giving it away free atm : https://www.origin.com/en-us/store/browse?q=titanfall
alidan
the gun on players is absolutely worthless, but the gun on the ai is good. the game is suppose to be fast paced, but it doesn't have the mechanics of an early ut or quake, if you are dieing to the smart pistol as a player... that means you suck as they had to hold that crap on you for 5 -7 seconds with ever losing track of you.
eklipz330
hasn't this already been the situation for the past 8 or 9 years?
right2myopinion
5-7 seconds for Smart Pistol Lock on? Who are you kidding? I love the way Smart Pistol users defend that gun to death. There's a reason why they love the gun so much... I used to use the Smart Pistol just to piss off people for the easy kills. Run and wait for it to auto lock on something... 4 targets locked, shoot, wow killed a pilot as a bonus. LOL. I'm just being honest!
closetwhisperer1
This one might actually feature compelling gameplay guys!!!-sarcasm
Aozora7
Last time I played with smart pistol it was absolutely overpowered and absolutely the best gun for any outdoors engagement, even on PC. Not only it does have a very solid TTK at moderate distances, it also requires no aiming whatsoever and allows you to move as much as you want when using it. If they nerfed lock-on time since then, it may be balanced now, but around november it felt like a cheat to me.
On top of that, it also provides instant NPC wave clear.
The only reason not to use smart pistol was being on a map when majority of combat happens in confined spaces.
alextheblue
It's not that bad. I prefer other distro platforms but it's not going to change my decision to play or not play a particular game. If you actually wanted to play a particular EA title on PC you'd have done so already, Origin or not.
rantoc
But but... thats like most console shooters that has any speed in them... =P
hixbot
The Smart Pistol is crap. It helps noobs with no skills get easy kills. and yes, that is incredibly lame.
But honestly, you'd have to be a noob to use it. If you have any skill at all, you'll get WAY more kills with other guns. So in that sense, the smart pistol is not overpowered at all, it's just a noob gun for noobs, period.
An overpowered gun would let skilled players dominate to a point that no other gun is useful. That is not the case with the smart pistol, skilled players don't wast any time with it.
hixbot :
I often get frustrated using the smart pistol during attrition matches where the gun does wonders for taking out grunts and spectres, but if I get into a gun fight with a pilot, I almost don't stand a chance because of the long lock-on time. Also, if you're cloaked and a pilot runs by without noticing you, you can kill them right away with a shottie, R97, LMG or any other gun before they can turn around. With the pistol, you have to wait for the lock-on and half the time, they jump somewhere out of your sights. I think it's good how they implemented it. The slow lock-on when targeting pilots is a definite equalizer.


text:
I used alcohol to cope with running a multimillion-dollar startup at 21. After getting the drunkest I've ever been at a work event, I resolved to get sober.
Kiera Fields Nov. 11, 2021, 11:30 AM
, 28, is now five years sober. He stepped back from his role as Social Chain's COO in 2019. Dom McGregor
Dom McGregor dropped out of university to cofound Social Chain, an agency now worth $US650 ($AU880) million.
He increasingly turned to alcohol while navigating the highs and lows of startup life in his 20s.
He decided to get sober after getting so drunk at a work event that his cofounder had to intervene.
This as-told-to article is based on a conversation with Dominic McGregor, a 28-year-old entrepreneur and cofounder of the social-media agency Social Chain, about his struggles with alcohol and how he got sober. It has been edited for length and clarity.
The roller coaster of founding a company now worth nine figures began with a single tweet sent from my university dorm bathroom in January 2013.
I remember waking up hungover and walking down to the bathroom to find no toilet paper.
Instead of alerting my housemates or heading out to buy some, I tweeted a picture of the empty roll: #studentproblems. I decided to start a new account just for tweeting about my life at university.
I had rapidly gained a following of about 50,000 followers when Steve Bartlett, my future cofounder, approached me in February 2013. He was trying to set up his own online business for students and wanted my help.
We met up in a bar. By the end of the night, he persuaded me to drop out of university and pursue the venture with him.
I was 19 at the time. We started growing different student-focused social-media accounts to draw traffic, but we quickly realized that the social-media influence was more valuable than the website trade. So we got rid of the website and doubled down on growing social-media assets.
As freelancers, we began marketing these social assets to companies to pay us to advertise their products, as well as drive traffic and downloads. In April 2014, we traveled together, working flexibly from our laptops in Thailand and Brazil.
At this point, we were bringing in six figures each by advising clients in London, San Francisco, and New York. And in August of that year, one of our clients wanted to invest.
I was 21, Steve was 22, and we'd been operating causally while funding a lifestyle of traveling. Taking investment meant settling down and accepting a lot more responsibility.
We decided to move back to London. And the jump from having to only hold ourselves accountable to having a staff of 10 was huge. Because social media was still in its infancy, it was difficult to find anyone who had experience. The average age of our team was 21.
On the client side, we were flying: winning awards, securing huge deals, growing rapidly. But internally there were cash-flow problems. We started working on a 250,000 pound (113,398kg) project, but we didn't get paid for 11 months. This was a recurring problem.
I was existing in two polar-opposite mindsets: I was an uber-successful 21-year-old with my own home and car. But I was also depressed and anxious, constantly thinking about HR issues, unpaid invoices, and delayed salaries.
In both situations, I would turn to alcohol. We had routine celebratory staff parties for every award we won and deal we made. But if I'd had a terrible day, I would go home to unwind with a drink.
This pattern worsened throughout our first year and into our second. By Christmas 2015, I was on a downward spiral. I'd function throughout the week, but then I'd fall apart over the weekends. I started isolating myself from my friends and colleagues.
One Friday night in the summer of 2016, I got the drunkest I'd ever been. For a few weeks, I'd been trying to limit myself to only one drink a night. Emboldened by my new self-control, I attended a nighttime work event. But it was obvious at this point that I was struggling with alcoholism.
I was derogatory toward one of my best friends and embarrassed myself in front of our entire team. When I woke up, Steve had texted me saying we needed to talk.
When he sat me down, I apologized. I felt broken.
It became a case of 'How do I rebuild myself and get sober?' I threw myself into work because that was what gave me stability and focus.
The most difficult part to accept was that it wasn't the success, the business, or Steve who was to blame for my problems. It was me. I think I always had the potential to become dependent on alcohol, but the pressure of becoming a successful founder accelerated it massively.
Slowly, I progressed. I don't remember much of the first five or six months. I walked around like a zombie. I had to remove myself from any social situation that would involve drinking. Although I was throwing myself into work, I had drawn a line between myself and the social aspects of the business.
At first, I wouldn't go to any events or after-work drinks. Steve and I were settling into roles as senior leadership, so distancing myself wasn't unheard of. I stayed at Social Chain as the COO for four years after this, working alongside Steve.
I think being sober made me a better founder, as well as a better person. It was an interesting point of conversation that people could approach me about.
I made friends with older peers who no longer drank and pregnant women at networking events – people who would have steered clear of drunk me.
My sobriety also came at a time when a natural divide needed to be formed between me and Steve as senior leadership and our employees. We needed that distance to effectively grow the company.
Going through that experience broke down any walls between me and Steve. We knew we could depend on each other for anything, and I think that was a major asset when growing our company.
Social Chain is now worth 500 million pounds, and although Steve and I have stepped back from our CEO and COO roles, respectively, we still chat often.
(Editor's note: In 2019, Social Chain merged with Lumaland AG and listed on the Frankfurt Stock Exchange. Its market cap as of November 10, 2021, was 565 million euros.)
Kiera Fields


text:
/*!
 * \file
 * \brief FBO stencilbuffer tests.
 *//*--------------------------------------------------------------------*/

#include "es3fFramebufferBlitTests.hpp"
#include "es3fFboTestCase.hpp"
#include "es3fFboTestUtil.hpp"
#include "gluTextureUtil.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuVectorUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuImageCompare.hpp"
#include "tcuRenderTarget.hpp"
#include "sglrContextUtil.hpp"
#include "glwEnums.hpp"
#include "deStringUtil.hpp"

namespace deqp
{
namespace gles3
{
namespace Functional
{

using std::string;
using tcu::TestLog;
using tcu::Vec2;
using tcu::Vec3;
using tcu::Vec4;
using tcu::IVec2;
using tcu::IVec3;
using tcu::IVec4;
using tcu::UVec4;
using namespace FboTestUtil;

class BlitRectCase : public FboTestCase
{
public:
	BlitRectCase (Context& context, const char* name, const char* desc, deUint32 filter, const IVec2& srcSize, const IVec4& srcRect, const IVec2& dstSize, const IVec4& dstRect, int cellSize = 8)
		: FboTestCase		(context, name, desc)
		, m_filter			(filter)
		, m_srcSize			(srcSize)
		, m_srcRect			(srcRect)
		, m_dstSize			(dstSize)
		, m_dstRect			(dstRect)
		, m_cellSize		(cellSize)
		, m_gridCellColorA	(0.2f, 0.7f, 0.1f, 1.0f)
		, m_gridCellColorB	(0.7f, 0.1f, 0.5f, 0.8f)
	{
	}

	void render (tcu::Surface& dst)
	{
		const deUint32			colorFormat		= GL_RGBA8;

		GradientShader			gradShader		(glu::TYPE_FLOAT_VEC4);
		Texture2DShader			texShader		(DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4);
		deUint32				gradShaderID	= getCurrentContext()->createProgram(&gradShader);
		deUint32				texShaderID		= getCurrentContext()->createProgram(&texShader);

		deUint32				srcFbo, dstFbo;
		deUint32				srcRbo, dstRbo;

		// Setup shaders
		gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
		texShader.setUniforms(*getCurrentContext(), texShaderID);

		// Create framebuffers.
		for (int ndx = 0; ndx < 2; ndx++)
		{
			deUint32&		fbo		= ndx ? dstFbo : srcFbo;
			deUint32&		rbo		= ndx ? dstRbo : srcRbo;
			const IVec2&	size	= ndx ? m_dstSize : m_srcSize;

			glGenFramebuffers(1, &fbo);
			glGenRenderbuffers(1, &rbo);

			glBindRenderbuffer(GL_RENDERBUFFER, rbo);
			glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, size.x(), size.y());

			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
			checkError();
			checkFramebufferStatus(GL_FRAMEBUFFER);
		}

		// Fill destination with gradient.
		glBindFramebuffer(GL_FRAMEBUFFER, dstFbo);
		glViewport(0, 0, m_dstSize.x(), m_dstSize.y());

		sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));

		// Fill source with grid pattern.
		{
			const deUint32		format		= GL_RGBA;
			const deUint32		dataType	= GL_UNSIGNED_BYTE;
			const int			texW		= m_srcSize.x();
			const int			texH		= m_srcSize.y();
			deUint32			gridTex		= 0;
			tcu::TextureLevel	data		(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);

			tcu::fillWithGrid(data.getAccess(), m_cellSize, m_gridCellColorA, m_gridCellColorB);

			glGenTextures(1, &gridTex);
			glBindTexture(GL_TEXTURE_2D, gridTex);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
			glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());

			glBindFramebuffer(GL_FRAMEBUFFER, srcFbo);
			glViewport(0, 0, m_srcSize.x(), m_srcSize.y());
			sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
		}

		// Perform copy.
		glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
		glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(), m_dstRect.z(), m_dstRect.w(), GL_COLOR_BUFFER_BIT, m_filter);

		// Read back results.
		glBindFramebuffer(GL_READ_FRAMEBUFFER, dstFbo);
		readPixels(dst, 0, 0, m_dstSize.x(), m_dstSize.y(), glu::mapGLInternalFormat(colorFormat), Vec4(1.0f), Vec4(0.0f));
	}

	virtual bool compare (const tcu::Surface& reference, const tcu::Surface& result)
	{
		// Use pixel-threshold compare for rect cases since 1px off will mean failure.
		tcu::RGBA threshold = TestCase::m_context.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(7,7,7,7);
		return tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, threshold, tcu::COMPARE_LOG_RESULT);
	}

protected:
	const deUint32	m_filter;
	const IVec2		m_srcSize;
	const IVec4		m_srcRect;
	const IVec2		m_dstSize;
	const IVec4		m_dstRect;
	const int		m_cellSize;
	const Vec4		m_gridCellColorA;
	const Vec4		m_gridCellColorB;
};

class BlitNearestFilterConsistencyCase : public BlitRectCase
{
public:
			BlitNearestFilterConsistencyCase	(Context& context, const char* name, const char* desc, const IVec2& srcSize, const IVec4& srcRect, const IVec2& dstSize, const IVec4& dstRect);

	bool	compare								(const tcu::Surface& reference, const tcu::Surface& result);
};

BlitNearestFilterConsistencyCase::BlitNearestFilterConsistencyCase (Context& context, const char* name, const char* desc, const IVec2& srcSize, const IVec4& srcRect, const IVec2& dstSize, const IVec4& dstRect)
	: BlitRectCase(context, name, desc, GL_NEAREST, srcSize, srcRect, dstSize, dstRect, 1)
{
}

bool BlitNearestFilterConsistencyCase::compare (const tcu::Surface& reference, const tcu::Surface& result)
{
	DE_ASSERT(reference.getWidth() == result.getWidth());
	DE_ASSERT(reference.getHeight() == result.getHeight());
	DE_UNREF(reference);

	// Image origin must be visible (for baseColor)
	DE_ASSERT(de::min(m_dstRect.x(), m_dstRect.z()) >= 0);
	DE_ASSERT(de::min(m_dstRect.y(), m_dstRect.w()) >= 0);

	const tcu::RGBA		cellColorA		(m_gridCellColorA);
	const tcu::RGBA		cellColorB		(m_gridCellColorB);
	const tcu::RGBA		threshold		= TestCase::m_context.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(7,7,7,7);
	const tcu::IVec4	destinationArea	= tcu::IVec4(de::clamp(de::min(m_dstRect.x(), m_dstRect.z()), 0, result.getWidth()),
													 de::clamp(de::min(m_dstRect.y(), m_dstRect.w()), 0, result.getHeight()),
													 de::clamp(de::max(m_dstRect.x(), m_dstRect.z()), 0, result.getWidth()),
													 de::clamp(de::max(m_dstRect.y(), m_dstRect.w()), 0, result.getHeight()));
	const tcu::RGBA		baseColor		= result.getPixel(destinationArea.x(), destinationArea.y());
	const bool			signConfig		= tcu::compareThreshold(baseColor, cellColorA, threshold);

	bool				error			= false;
	tcu::Surface		errorMask		(result.getWidth(), result.getHeight());
	std::vector<bool>	horisontalSign	(destinationArea.z() - destinationArea.x());
	std::vector<bool>	verticalSign	(destinationArea.w() - destinationArea.y());

	tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));

	// Checking only area in our destination rect

	m_testCtx.getLog()
		<< tcu::TestLog::Message
		<< "Verifying consistency of NEAREST filtering. Verifying rect " << m_dstRect << ".\n"
		<< "Rounding direction of the NEAREST filter at the horisontal texel edge (x = n + 0.5) should not depend on the y-coordinate.\n"
		<< "Rounding direction of the NEAREST filter at the vertical texel edge (y = n + 0.5) should not depend on the x-coordinate.\n"
		<< "Blitting a grid (with uniform sized cells) should result in a grid (with non-uniform sized cells)."
		<< tcu::TestLog::EndMessage;

	// Verify that destination only contains valid colors

	for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy)
	for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx)
	{
		const tcu::RGBA	color	= result.getPixel(destinationArea.x() + dx, destinationArea.y() + dy);
		const bool isValidColor = tcu::compareThreshold(color, cellColorA, threshold) || tcu::compareThreshold(color, cellColorB, threshold);

		if (!isValidColor)
		{
			errorMask.setPixel(destinationArea.x() + dx, destinationArea.y() + dy, tcu::RGBA::red);
			error = true;
		}
	}
	if (error)
	{
		m_testCtx.getLog()
			<< tcu::TestLog::Message
			<< "Image verification failed, destination rect contains unexpected values. "
			<< "Expected either " << cellColorA << " or " << cellColorB << "."
			<< tcu::TestLog::EndMessage
			<< tcu::TestLog::ImageSet("Result", "Image verification result")
			<< tcu::TestLog::Image("Result",	"Result",		result)
			<< tcu::TestLog::Image("ErrorMask",	"Error mask",	errorMask)
			<< tcu::TestLog::EndImageSet;
		return false;
	}

	// Detect result edges by reading the first row and first column of the blitted area.
	// Blitting a grid should result in a grid-like image. ("sign changes" should be consistent)

	for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx)
	{
		const tcu::RGBA color = result.getPixel(destinationArea.x() + dx, destinationArea.y());

		if (tcu::compareThreshold(color, cellColorA, threshold))
			horisontalSign[dx] = true;
		else if (tcu::compareThreshold(color, cellColorB, threshold))
			horisontalSign[dx] = false;
		else
			DE_ASSERT(DE_FALSE);
	}
	for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy)
	{
		const tcu::RGBA color = result.getPixel(destinationArea.x(), destinationArea.y() + dy);

		if (tcu::compareThreshold(color, cellColorA, threshold))
			verticalSign[dy] = true;
		else if (tcu::compareThreshold(color, cellColorB, threshold))
			verticalSign[dy] = false;
		else
			DE_ASSERT(DE_FALSE);
	}

	// Verify grid-like image

	for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy)
	for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx)
	{
		const tcu::RGBA	color		= result.getPixel(destinationArea.x() + dx, destinationArea.y() + dy);
		const bool		resultSign	= tcu::compareThreshold(cellColorA, color, threshold);
		const bool		correctSign	= (horisontalSign[dx] == verticalSign[dy]) == signConfig;

		if (resultSign != correctSign)
		{
			errorMask.setPixel(destinationArea.x() + dx, destinationArea.y() + dy, tcu::RGBA::red);
			error = true;
		}
	}

	// Report result

	if (error)
	{
		m_testCtx.getLog()
			<< tcu::TestLog::Message
			<< "Image verification failed, nearest filter is not consistent."
			<< tcu::TestLog::EndMessage
			<< tcu::TestLog::ImageSet("Result", "Image verification result")
			<< tcu::TestLog::Image("Result",	"Result",		result)
			<< tcu::TestLog::Image("ErrorMask",	"Error mask",	errorMask)
			<< tcu::TestLog::EndImageSet;
	}
	else
	{
		m_testCtx.getLog()
			<< tcu::TestLog::Message
			<< "Image verification passed."
			<< tcu::TestLog::EndMessage
			<< tcu::TestLog::ImageSet("Result", "Image verification result")
			<< tcu::TestLog::Image("Result", "Result", result)
			<< tcu::TestLog::EndImageSet;
	}

	return !error;
}

static tcu::BVec4 getChannelMask (tcu::TextureFormat::ChannelOrder order)
{
	switch (order)
	{
		case tcu::TextureFormat::R:		return tcu::BVec4(true,	false,	false,	false);
		case tcu::TextureFormat::RG:	return tcu::BVec4(true,	true,	false,	false);
		case tcu::TextureFormat::RGB:	return tcu::BVec4(true,	true,	true,	false);
		case tcu::TextureFormat::RGBA:	return tcu::BVec4(true,	true,	true,	true);
		case tcu::TextureFormat::sRGB:	return tcu::BVec4(true,	true,	true,	false);
		case tcu::TextureFormat::sRGBA:	return tcu::BVec4(true,	true,	true,	true);
		default:
			DE_ASSERT(false);
			return tcu::BVec4(false);
	}
}

class BlitColorConversionCase : public FboTestCase
{
public:
	BlitColorConversionCase (Context& context, const char* name, const char* desc, deUint32 srcFormat, deUint32 dstFormat, const IVec2& size)
		: FboTestCase	(context, name, desc)
		, m_srcFormat	(srcFormat)
		, m_dstFormat	(dstFormat)
		, m_size		(size)
	{
	}

protected:
	void preCheck (void)
	{
		checkFormatSupport(m_srcFormat);
		checkFormatSupport(m_dstFormat);
	}

	void render (tcu::Surface& dst)
	{
		tcu::TextureFormat		srcFormat			= glu::mapGLInternalFormat(m_srcFormat);
		tcu::TextureFormat		dstFormat			= glu::mapGLInternalFormat(m_dstFormat);
		glu::DataType			srcOutputType		= getFragmentOutputType(srcFormat);
		glu::DataType			dstOutputType		= getFragmentOutputType(dstFormat);

		// Compute ranges \note Doesn't handle case where src or dest is not subset of the another!
		tcu::TextureFormatInfo	srcFmtRangeInfo		= tcu::getTextureFormatInfo(srcFormat);
		tcu::TextureFormatInfo	dstFmtRangeInfo		= tcu::getTextureFormatInfo(dstFormat);
		tcu::BVec4				copyMask			= tcu::logicalAnd(getChannelMask(srcFormat.order), getChannelMask(dstFormat.order));
		tcu::BVec4				srcIsGreater		= tcu::greaterThan(srcFmtRangeInfo.valueMax-srcFmtRangeInfo.valueMin, dstFmtRangeInfo.valueMax-dstFmtRangeInfo.valueMin);
		tcu::TextureFormatInfo	srcRangeInfo		(tcu::select(dstFmtRangeInfo.valueMin,		srcFmtRangeInfo.valueMin,		tcu::logicalAnd(copyMask, srcIsGreater)),
													 tcu::select(dstFmtRangeInfo.valueMax,		srcFmtRangeInfo.valueMax,		tcu::logicalAnd(copyMask, srcIsGreater)),
													 tcu::select(dstFmtRangeInfo.lookupScale,	srcFmtRangeInfo.lookupScale,	tcu::logicalAnd(copyMask, srcIsGreater)),
													 tcu::select(dstFmtRangeInfo.lookupBias,	srcFmtRangeInfo.lookupBias,		tcu::logicalAnd(copyMask, srcIsGreater)));
		tcu::TextureFormatInfo	dstRangeInfo		(tcu::select(dstFmtRangeInfo.valueMin,		srcFmtRangeInfo.valueMin,		tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)),
													 tcu::select(dstFmtRangeInfo.valueMax,		srcFmtRangeInfo.valueMax,		tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)),
													 tcu::select(dstFmtRangeInfo.lookupScale,	srcFmtRangeInfo.lookupScale,	tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)),
													 tcu::select(dstFmtRangeInfo.lookupBias,	srcFmtRangeInfo.lookupBias,		tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)));

		// Shaders.
		GradientShader			gradientToSrcShader	(srcOutputType);
		GradientShader			gradientToDstShader	(dstOutputType);

		deUint32				gradShaderSrcID		= getCurrentContext()->createProgram(&gradientToSrcShader);
		deUint32				gradShaderDstID		= getCurrentContext()->createProgram(&gradientToDstShader);

		deUint32				srcFbo, dstFbo;
		deUint32				srcRbo, dstRbo;

		// Create framebuffers.
		for (int ndx = 0; ndx < 2; ndx++)
		{
			deUint32&	fbo		= ndx ? dstFbo : srcFbo;
			deUint32&	rbo		= ndx ? dstRbo : srcRbo;
			deUint32	format	= ndx ? m_dstFormat : m_srcFormat;

			glGenFramebuffers(1, &fbo);
			glGenRenderbuffers(1, &rbo);

			glBindRenderbuffer(GL_RENDERBUFFER, rbo);
			glRenderbufferStorage(GL_RENDERBUFFER, format, m_size.x(), m_size.y());

			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
			checkError();
			checkFramebufferStatus(GL_FRAMEBUFFER);
		}

		glViewport(0, 0, m_size.x(), m_size.y());

		// Render gradients.
		for (int ndx = 0; ndx < 2; ndx++)
		{
			glBindFramebuffer(GL_FRAMEBUFFER, ndx ? dstFbo : srcFbo);

			if (ndx)
			{
				gradientToDstShader.setGradient(*getCurrentContext(), gradShaderDstID, dstRangeInfo.valueMax, dstRangeInfo.valueMin);
				sglr::drawQuad(*getCurrentContext(), gradShaderDstID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
			}
			else
			{
				gradientToSrcShader.setGradient(*getCurrentContext(), gradShaderSrcID, srcRangeInfo.valueMin, dstRangeInfo.valueMax);
				sglr::drawQuad(*getCurrentContext(), gradShaderSrcID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
			}
		}

		// Execute copy.
		glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
		glBlitFramebuffer(0, 0, m_size.x(), m_size.y(), 0, 0, m_size.x(), m_size.y(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
		checkError();

		// Read results.
		glBindFramebuffer(GL_READ_FRAMEBUFFER, dstFbo);
		readPixels(dst, 0, 0, m_size.x(), m_size.y(), dstFormat, dstRangeInfo.lookupScale, dstRangeInfo.lookupBias);
	}

	bool compare (const tcu::Surface& reference, const tcu::Surface& result)
	{
		const tcu::TextureFormat	srcFormat	= glu::mapGLInternalFormat(m_srcFormat);
		const tcu::TextureFormat	dstFormat	= glu::mapGLInternalFormat(m_dstFormat);
		const bool					srcIsSRGB	= tcu::isSRGB(srcFormat);
		const bool					dstIsSRGB	= tcu::isSRGB(dstFormat);

		tcu::RGBA					threshold;

		if (dstIsSRGB)
		{
			threshold = getToSRGBConversionThreshold(srcFormat, dstFormat);
		}
		else
		{
			const tcu::RGBA	srcMaxDiff	= getFormatThreshold(srcFormat) * (srcIsSRGB ? 2 : 1);
			const tcu::RGBA	dstMaxDiff	= getFormatThreshold(dstFormat);

			threshold = tcu::max(srcMaxDiff, dstMaxDiff);
		}

		m_testCtx.getLog() << tcu::TestLog::Message << "threshold = " << threshold << tcu::TestLog::EndMessage;
		return tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, threshold, tcu::COMPARE_LOG_RESULT);
	}

private:
	deUint32		m_srcFormat;
	deUint32		m_dstFormat;
	IVec2			m_size;
};

class BlitDepthStencilCase : public FboTestCase
{
public:
	BlitDepthStencilCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 srcBuffers, const IVec2& srcSize, const IVec4& srcRect, deUint32 dstBuffers, const IVec2& dstSize, const IVec4& dstRect, deUint32 copyBuffers)
		: FboTestCase	(context, name, desc)
		, m_format		(format)
		, m_srcBuffers	(srcBuffers)
		, m_srcSize		(srcSize)
		, m_srcRect		(srcRect)
		, m_dstBuffers	(dstBuffers)
		, m_dstSize		(dstSize)
		, m_dstRect		(dstRect)
		, m_copyBuffers	(copyBuffers)
	{
	}

protected:
	void preCheck (void)
	{
		checkFormatSupport(m_format);
	}

	void render (tcu::Surface& dst)
	{
		const deUint32			colorFormat			= GL_RGBA8;

		GradientShader			gradShader			(glu::TYPE_FLOAT_VEC4);
		Texture2DShader			texShader			(DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4);
		FlatColorShader			flatShader			(glu::TYPE_FLOAT_VEC4);

		deUint32				flatShaderID		= getCurrentContext()->createProgram(&flatShader);
		deUint32				texShaderID			= getCurrentContext()->createProgram(&texShader);
		deUint32				gradShaderID		= getCurrentContext()->createProgram(&gradShader);

		deUint32				srcFbo				= 0;
		deUint32				dstFbo				= 0;
		deUint32				srcColorRbo			= 0;
		deUint32				dstColorRbo			= 0;
		deUint32				srcDepthStencilRbo	= 0;
		deUint32				dstDepthStencilRbo	= 0;

		// setup shaders
		gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
		texShader.setUniforms(*getCurrentContext(), texShaderID);

		// Create framebuffers.
		for (int ndx = 0; ndx < 2; ndx++)
		{
			deUint32&		fbo				= ndx ? dstFbo : srcFbo;
			deUint32&		colorRbo		= ndx ? dstColorRbo : srcColorRbo;
			deUint32&		depthStencilRbo	= ndx ? dstDepthStencilRbo : srcDepthStencilRbo;
			deUint32		bufs			= ndx ? m_dstBuffers : m_srcBuffers;
			const IVec2&	size			= ndx ? m_dstSize : m_srcSize;

			glGenFramebuffers(1, &fbo);
			glGenRenderbuffers(1, &colorRbo);
			glGenRenderbuffers(1, &depthStencilRbo);

			glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
			glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, size.x(), size.y());

			glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo);
			glRenderbufferStorage(GL_RENDERBUFFER, m_format, size.x(), size.y());

			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);

			if (bufs & GL_DEPTH_BUFFER_BIT)
				glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
			if (bufs & GL_STENCIL_BUFFER_BIT)
				glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);

			checkError();
			checkFramebufferStatus(GL_FRAMEBUFFER);

			// Clear depth to 1 and stencil to 0.
			glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
		}

		// Fill source with gradient, depth = [-1..1], stencil = 7
		glBindFramebuffer(GL_FRAMEBUFFER, srcFbo);
		glViewport(0, 0, m_srcSize.x(), m_srcSize.y());
		glEnable(GL_DEPTH_TEST);
		glEnable(GL_STENCIL_TEST);
		glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
		glStencilFunc(GL_ALWAYS, 7, 0xffu);

		sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));

		// Fill destination with grid pattern, depth = 0 and stencil = 1
		{
			const deUint32		format		= GL_RGBA;
			const deUint32		dataType	= GL_UNSIGNED_BYTE;
			const int			texW		= m_srcSize.x();
			const int			texH		= m_srcSize.y();
			deUint32			gridTex		= 0;
			tcu::TextureLevel	data		(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);

			tcu::fillWithGrid(data.getAccess(), 8, Vec4(0.2f, 0.7f, 0.1f, 1.0f), Vec4(0.7f, 0.1f, 0.5f, 0.8f));

			glGenTextures(1, &gridTex);
			glBindTexture(GL_TEXTURE_2D, gridTex);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
			glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());

			glBindFramebuffer(GL_FRAMEBUFFER, dstFbo);
			glViewport(0, 0, m_dstSize.x(), m_dstSize.y());
			glStencilFunc(GL_ALWAYS, 1, 0xffu);
			sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
		}

		// Perform copy.
		glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
		glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(), m_dstRect.z(), m_dstRect.w(), m_copyBuffers, GL_NEAREST);

		// Render blue color where depth < 0, decrement on depth failure.
		glBindFramebuffer(GL_FRAMEBUFFER, dstFbo);
		glViewport(0, 0, m_dstSize.x(), m_dstSize.y());
		glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
		glStencilFunc(GL_ALWAYS, 0, 0xffu);

		flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f));
		sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));

		if (m_dstBuffers & GL_STENCIL_BUFFER_BIT)
		{
			// Render green color where stencil == 6.
			glDisable(GL_DEPTH_TEST);
			glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
			glStencilFunc(GL_EQUAL, 6, 0xffu);

			flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
			sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
		}

		readPixels(dst, 0, 0, m_dstSize.x(), m_dstSize.y(), glu::mapGLInternalFormat(colorFormat), Vec4(1.0f), Vec4(0.0f));
	}

private:
	deUint32	m_format;
	deUint32	m_srcBuffers;
	IVec2		m_srcSize;
	IVec4		m_srcRect;
	deUint32	m_dstBuffers;
	IVec2		m_dstSize;
	IVec4		m_dstRect;
	deUint32	m_copyBuffers;
};

class BlitDefaultFramebufferCase : public FboTestCase
{
public:
	BlitDefaultFramebufferCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 filter)
		: FboTestCase	(context, name, desc)
		, m_format		(format)
		, m_filter		(filter)
	{
	}

protected:
	void preCheck (void)
	{
		if (m_context.getRenderTarget().getNumSamples() > 0)
			throw tcu::NotSupportedError("Not supported in MSAA config");

		checkFormatSupport(m_format);
	}

	virtual void render (tcu::Surface& dst)
	{
		tcu::TextureFormat		colorFormat		= glu::mapGLInternalFormat(m_format);
		glu::TransferFormat		transferFmt		= glu::getTransferFormat(colorFormat);
		GradientShader			gradShader		(glu::TYPE_FLOAT_VEC4);
		Texture2DShader			texShader		(DataTypes() << glu::getSampler2DType(colorFormat), glu::TYPE_FLOAT_VEC4);
		deUint32				gradShaderID	= getCurrentContext()->createProgram(&gradShader);
		deUint32				texShaderID		= getCurrentContext()->createProgram(&texShader);
		deUint32				fbo				= 0;
		deUint32				tex				= 0;
		const int				texW			= 128;
		const int				texH			= 128;

		// Setup shaders
		gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
		texShader.setUniforms(*getCurrentContext(), texShaderID);

		// FBO
		glGenFramebuffers(1, &fbo);
		glGenTextures(1, &tex);

		glBindTexture(GL_TEXTURE_2D, tex);
		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	m_filter);
		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	m_filter);
		glTexImage2D(GL_TEXTURE_2D, 0, m_format, texW, texH, 0, transferFmt.format, transferFmt.dataType, DE_NULL);

		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
		checkError();
		checkFramebufferStatus(GL_FRAMEBUFFER);

		// Render gradient to screen.
		glBindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());

		sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));

		// Blit gradient from screen to fbo.
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
		glBlitFramebuffer(0, 0, getWidth(), getHeight(), 0, 0, texW, texH, GL_COLOR_BUFFER_BIT, m_filter);

		// Fill left half of viewport with quad that uses texture.
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
		glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 0.0f, 0.0f, 1.0f).getPtr());
		sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(0.0f, 1.0f, 0.0f));

		// Blit fbo to right half.
		glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
		glBlitFramebuffer(0, 0, texW, texH, getWidth()/2, 0, getWidth(), getHeight(), GL_COLOR_BUFFER_BIT, m_filter);

		glBindFramebuffer(GL_READ_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
		readPixels(dst, 0, 0, getWidth(), getHeight());
	}

	bool compare (const tcu::Surface& reference, const tcu::Surface& result)
	{
		const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_format), tcu::RGBA(12, 12, 12, 12)));

		m_testCtx.getLog() << TestLog::Message << "Comparing images, threshold: " << threshold << TestLog::EndMessage;

		return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
	}

protected:
	const deUint32	m_format;
	const deUint32	m_filter;
};

class DefaultFramebufferBlitCase : public BlitDefaultFramebufferCase
{
public:
	enum BlitDirection
	{
		BLIT_DEFAULT_TO_TARGET,
		BLIT_TO_DEFAULT_FROM_TARGET,

		BLIT_LAST
	};
	enum BlitArea
	{
		AREA_SCALE,
		AREA_OUT_OF_BOUNDS,

		AREA_LAST
	};

	DefaultFramebufferBlitCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 filter, BlitDirection dir, BlitArea area)
		: BlitDefaultFramebufferCase	(context, name, desc, format, filter)
		, m_blitDir						(dir)
		, m_blitArea					(area)
		, m_srcRect						(-1, -1, -1, -1)
		, m_dstRect						(-1, -1, -1, -1)
		, m_interestingArea				(-1, -1, -1, -1)
	{
		DE_ASSERT(dir < BLIT_LAST);
		DE_ASSERT(area < AREA_LAST);
	}

	void init (void)
	{
		// requirements
		const int minViewportSize = 128;
		if (m_context.getRenderTarget().getWidth() < minViewportSize || m_context.getRenderTarget().getHeight() < minViewportSize)
			throw tcu::NotSupportedError("Viewport size " + de::toString(minViewportSize) + "x" + de::toString(minViewportSize) + " required");

		// prevent viewport randoming
		m_viewportWidth = m_context.getRenderTarget().getWidth();
		m_viewportHeight = m_context.getRenderTarget().getHeight();

		// set proper areas
		if (m_blitArea == AREA_SCALE)
		{
			m_srcRect = IVec4( 10,  20,  65, 100);
			m_dstRect = IVec4( 25,  30, 125,  94);
			m_interestingArea = IVec4(0, 0, 128, 128);
		}
		else if (m_blitArea == AREA_OUT_OF_BOUNDS)
		{
			const tcu::IVec2 ubound = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (tcu::IVec2(128, 128)) : (tcu::IVec2(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight()));

			m_srcRect = IVec4(-10, -15, 100,  63);
			m_dstRect = ubound.swizzle(0, 1, 0, 1) + IVec4(-75, -99, 8, 16);
			m_interestingArea = IVec4(ubound.x() - 128, ubound.y() - 128, ubound.x(), ubound.y());
		}
		else
			DE_ASSERT(false);
	}

	void render (tcu::Surface& dst)
	{
		const tcu::TextureFormat		colorFormat		= glu::mapGLInternalFormat(m_format);
		const glu::TransferFormat		transferFmt		= glu::getTransferFormat(colorFormat);
		const tcu::TextureChannelClass	targetClass		= (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (tcu::getTextureChannelClass(colorFormat.type)) : (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT);
		deUint32						fbo				= 0;
		deUint32						fboTex			= 0;
		const int						fboTexW			= 128;
		const int						fboTexH			= 128;
		const int						sourceWidth		= (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (getWidth()) : (fboTexW);
		const int						sourceHeight	= (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (getHeight()) : (fboTexH);
		const int						gridRenderWidth	= de::min(256, sourceWidth);
		const int						gridRenderHeight= de::min(256, sourceHeight);

		int								targetFbo		= -1;
		int								sourceFbo		= -1;

		// FBO
		glGenFramebuffers(1, &fbo);
		glGenTextures(1, &fboTex);

		glBindTexture(GL_TEXTURE_2D, fboTex);
		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	m_filter);
		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	m_filter);
		glTexImage2D(GL_TEXTURE_2D, 0, m_format, fboTexW, fboTexH, 0, transferFmt.format, transferFmt.dataType, DE_NULL);

		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
		checkError();
		checkFramebufferStatus(GL_FRAMEBUFFER);

		targetFbo = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (fbo) : (m_context.getRenderContext().getDefaultFramebuffer());
		sourceFbo = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (m_context.getRenderContext().getDefaultFramebuffer()) : (fbo);

		// Render grid to source framebuffer
		{
			Texture2DShader		texShader		(DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4);
			const deUint32		texShaderID		= getCurrentContext()->createProgram(&texShader);
			const deUint32		internalFormat	= GL_RGBA8;
			const deUint32		format			= GL_RGBA;
			const deUint32		dataType		= GL_UNSIGNED_BYTE;
			const int			gridTexW		= 128;
			const int			gridTexH		= 128;
			deUint32			gridTex			= 0;
			tcu::TextureLevel	data			(glu::mapGLTransferFormat(format, dataType), gridTexW, gridTexH, 1);

			tcu::fillWithGrid(data.getAccess(), 9, tcu::Vec4(0.9f, 0.5f, 0.1f, 0.9f), tcu::Vec4(0.2f, 0.8f, 0.2f, 0.7f));

			glGenTextures(1, &gridTex);
			glBindTexture(GL_TEXTURE_2D, gridTex);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
			glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, gridTexW, gridTexH, 0, format, dataType, data.getAccess().getDataPtr());

			glBindFramebuffer(GL_FRAMEBUFFER, sourceFbo);
			glViewport(0, 0, gridRenderWidth, gridRenderHeight);
			glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 0.0f, 0.0f, 1.0f).getPtr());

			texShader.setUniforms(*getCurrentContext(), texShaderID);
			sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
			glUseProgram(0);
		}

		// Blit source framebuffer to destination

		glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFbo);
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFbo);
		checkError();

		if (targetClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || targetClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT || targetClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
			glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 1.0f, 0.0f, 1.0f).getPtr());
		else if (targetClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
			glClearBufferiv(GL_COLOR, 0, IVec4(0, 0, 0, 0).getPtr());
		else if (targetClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
			glClearBufferuiv(GL_COLOR, 0, UVec4(0, 0, 0, 0).getPtr());
		else
			DE_ASSERT(false);

		glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(), m_dstRect.z(), m_dstRect.w(), GL_COLOR_BUFFER_BIT, m_filter);
		checkError();

		// Read target

		glBindFramebuffer(GL_FRAMEBUFFER, targetFbo);

		if (m_blitDir == BLIT_TO_DEFAULT_FROM_TARGET)
			readPixels(dst, m_interestingArea.x(), m_interestingArea.y(), m_interestingArea.z() - m_interestingArea.x(), m_interestingArea.w() - m_interestingArea.y());
		else
			readPixels(dst, m_interestingArea.x(), m_interestingArea.y(), m_interestingArea.z() - m_interestingArea.x(), m_interestingArea.w() - m_interestingArea.y(), colorFormat, tcu::Vec4(1.0f), tcu::Vec4(0.0f));

		checkError();
	}

private:
	const BlitDirection	m_blitDir;
	const BlitArea		m_blitArea;
	tcu::IVec4			m_srcRect;
	tcu::IVec4			m_dstRect;
	tcu::IVec4			m_interestingArea;
};

FramebufferBlitTests::FramebufferBlitTests (Context& context)
	: TestCaseGroup(context, "blit", "Framebuffer blit tests")
{
}

FramebufferBlitTests::~FramebufferBlitTests (void)
{
}

void FramebufferBlitTests::init (void)
{
	static const deUint32 colorFormats[] =
	{
		// RGBA formats
		GL_RGBA32I,
		GL_RGBA32UI,
		GL_RGBA16I,
		GL_RGBA16UI,
		GL_RGBA8,
		GL_RGBA8I,
		GL_RGBA8UI,
		GL_SRGB8_ALPHA8,
		GL_RGB10_A2,
		GL_RGB10_A2UI,
		GL_RGBA4,
		GL_RGB5_A1,

		// RGB formats
		GL_RGB8,
		GL_RGB565,

		// RG formats
		GL_RG32I,
		GL_RG32UI,
		GL_RG16I,
		GL_RG16UI,
		GL_RG8,
		GL_RG8I,
		GL_RG8UI,

		// R formats
		GL_R32I,
		GL_R32UI,
		GL_R16I,
		GL_R16UI,
		GL_R8,
		GL_R8I,
		GL_R8UI,

		// GL_EXT_color_buffer_float
		GL_RGBA32F,
		GL_RGBA16F,
		GL_R11F_G11F_B10F,
		GL_RG32F,
		GL_RG16F,
		GL_R32F,
		GL_R16F
	};

	static const deUint32 depthStencilFormats[] =
	{
		GL_DEPTH_COMPONENT32F,
		GL_DEPTH_COMPONENT24,
		GL_DEPTH_COMPONENT16,
		GL_DEPTH32F_STENCIL8,
		GL_DEPTH24_STENCIL8,
		GL_STENCIL_INDEX8
	};

	// .rect
	{
		static const struct
		{
			const char*	name;
			IVec4		srcRect;
			IVec4		dstRect;
		} copyRects[] =
		{
			{ "basic",						IVec4( 10,  20,  65, 100),		IVec4( 45,   5, 100,  85) },
			{ "scale",						IVec4( 10,  20,  65, 100),		IVec4( 25,  30, 125,  94) },
			{ "out_of_bounds",				IVec4(-10, -15, 100,  63),		IVec4( 50,  30, 136, 144) },
		};

		static const struct
		{
			const char*	name;
			IVec4		srcRect;
			IVec4		dstRect;
		} filterConsistencyRects[] =
		{
			{ "mag",						IVec4( 20,  10,  74, 88),		IVec4( 10,  10,  91, 101) },
			{ "min",						IVec4( 10,  20,  78, 100),		IVec4( 20,  20,  71,  80) },
			{ "out_of_bounds_mag",			IVec4( 21,  10,  73, 82),		IVec4( 11,  43, 141, 151) },
			{ "out_of_bounds_min",			IVec4( 11,  21,  77, 97),		IVec4( 80,  82, 135, 139) },
		};

		static const struct
		{
			const char* name;
			IVec4		srcSwizzle;
			IVec4		dstSwizzle;
		} swizzles[] =
		{
			{ DE_NULL,				IVec4(0,1,2,3),	IVec4(0,1,2,3) },
			{ "reverse_src_x",		IVec4(2,1,0,3), IVec4(0,1,2,3) },
			{ "reverse_src_y",		IVec4(0,3,2,1), IVec4(0,1,2,3) },
			{ "reverse_dst_x",		IVec4(0,1,2,3), IVec4(2,1,0,3) },
			{ "reverse_dst_y",		IVec4(0,1,2,3), IVec4(0,3,2,1) },
			{ "reverse_src_dst_x",	IVec4(2,1,0,3), IVec4(2,1,0,3) },
			{ "reverse_src_dst_y",	IVec4(0,3,2,1), IVec4(0,3,2,1) }
		};

		const IVec2 srcSize(127, 119);
		const IVec2 dstSize(132, 128);

		// Blit rectangle tests.
		tcu::TestCaseGroup* rectGroup = new tcu::TestCaseGroup(m_testCtx, "rect", "Blit rectangle tests");
		addChild(rectGroup);
		for (int rectNdx = 0; rectNdx < DE_LENGTH_OF_ARRAY(copyRects); rectNdx++)
		{
			for (int swzNdx = 0; swzNdx < DE_LENGTH_OF_ARRAY(swizzles); swzNdx++)
			{
				string		name	= string(copyRects[rectNdx].name) + (swizzles[swzNdx].name ? (string("_") + swizzles[swzNdx].name) : string());
				IVec4		srcSwz	= swizzles[swzNdx].srcSwizzle;
				IVec4		dstSwz	= swizzles[swzNdx].dstSwizzle;
				IVec4		srcRect	= copyRects[rectNdx].srcRect.swizzle(srcSwz[0], srcSwz[1], srcSwz[2], srcSwz[3]);
				IVec4		dstRect	= copyRects[rectNdx].dstRect.swizzle(dstSwz[0], dstSwz[1], dstSwz[2], dstSwz[3]);

				rectGroup->addChild(new BlitRectCase(m_context, (name + "_nearest").c_str(),	"", GL_NEAREST,	srcSize, srcRect, dstSize, dstRect));
				rectGroup->addChild(new BlitRectCase(m_context, (name + "_linear").c_str(),		"", GL_LINEAR,	srcSize, srcRect, dstSize, dstRect));
			}
		}

		// Nearest filter tests
		for (int rectNdx = 0; rectNdx < DE_LENGTH_OF_ARRAY(filterConsistencyRects); rectNdx++)
		{
			for (int swzNdx = 0; swzNdx < DE_LENGTH_OF_ARRAY(swizzles); swzNdx++)
			{
				string		name	= string("nearest_consistency_") + filterConsistencyRects[rectNdx].name + (swizzles[swzNdx].name ? (string("_") + swizzles[swzNdx].name) : string());
				IVec4		srcSwz	= swizzles[swzNdx].srcSwizzle;
				IVec4		dstSwz	= swizzles[swzNdx].dstSwizzle;
				IVec4		srcRect	= filterConsistencyRects[rectNdx].srcRect.swizzle(srcSwz[0], srcSwz[1], srcSwz[2], srcSwz[3]);
				IVec4		dstRect	= filterConsistencyRects[rectNdx].dstRect.swizzle(dstSwz[0], dstSwz[1], dstSwz[2], dstSwz[3]);

				rectGroup->addChild(new BlitNearestFilterConsistencyCase(m_context, name.c_str(), "Test consistency of the nearest filter", srcSize, srcRect, dstSize, dstRect));
			}
		}
	}

	// .conversion
	{
		tcu::TestCaseGroup* conversionGroup = new tcu::TestCaseGroup(m_testCtx, "conversion", "Color conversion tests");
		addChild(conversionGroup);

		for (int srcFmtNdx = 0; srcFmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); srcFmtNdx++)
		{
			for (int dstFmtNdx = 0; dstFmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); dstFmtNdx++)
			{
				deUint32					srcFormat	= colorFormats[srcFmtNdx];
				tcu::TextureFormat			srcTexFmt	= glu::mapGLInternalFormat(srcFormat);
				tcu::TextureChannelClass	srcType		= tcu::getTextureChannelClass(srcTexFmt.type);
				deUint32					dstFormat	= colorFormats[dstFmtNdx];
				tcu::TextureFormat			dstTexFmt	= glu::mapGLInternalFormat(dstFormat);
				tcu::TextureChannelClass	dstType		= tcu::getTextureChannelClass(dstTexFmt.type);

				if (((srcType == tcu::TEXTURECHANNELCLASS_FLOATING_POINT || srcType == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) !=
					 (dstType == tcu::TEXTURECHANNELCLASS_FLOATING_POINT || dstType == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)) ||
					((srcType == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER) != (dstType == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)) ||
					((srcType == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) != (dstType == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)))
					continue; // Conversion not supported.

				string						name		= string(getFormatName(srcFormat)) + "_to_" + getFormatName(dstFormat);

				conversionGroup->addChild(new BlitColorConversionCase(m_context, name.c_str(), "", srcFormat, dstFormat, IVec2(127, 113)));
			}
		}
	}

	// .depth_stencil
	{
		tcu::TestCaseGroup* depthStencilGroup = new tcu::TestCaseGroup(m_testCtx, "depth_stencil", "Depth and stencil blits");
		addChild(depthStencilGroup);

		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(depthStencilFormats); fmtNdx++)
		{
			deUint32			format		= depthStencilFormats[fmtNdx];
			tcu::TextureFormat	texFmt		= glu::mapGLInternalFormat(format);
			string				fmtName		= getFormatName(format);
			bool				depth		= texFmt.order == tcu::TextureFormat::D || texFmt.order == tcu::TextureFormat::DS;
			bool				stencil		= texFmt.order == tcu::TextureFormat::S || texFmt.order == tcu::TextureFormat::DS;
			deUint32			buffers		= (depth ? GL_DEPTH_BUFFER_BIT : 0) | (stencil ? GL_STENCIL_BUFFER_BIT : 0);

			depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_basic").c_str(), "", format, buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers));
			depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_scale").c_str(), "", format, buffers, IVec2(127, 119), IVec4(10, 30, 100, 70), buffers, IVec2(111, 130), IVec4(20, 5, 80, 130), buffers));

			if (depth && stencil)
			{
				depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_depth_only").c_str(),		"", format, buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), GL_DEPTH_BUFFER_BIT));
				depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_stencil_only").c_str(),	"", format, buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), GL_STENCIL_BUFFER_BIT));
			}
		}
	}

	// .default_framebuffer
	{
		static const struct
		{
			const char*								name;
			DefaultFramebufferBlitCase::BlitArea	area;
		} areas[] =
		{
			{ "scale",						DefaultFramebufferBlitCase::AREA_SCALE			},
			{ "out_of_bounds",				DefaultFramebufferBlitCase::AREA_OUT_OF_BOUNDS	},
		};

		tcu::TestCaseGroup* defaultFbGroup = new tcu::TestCaseGroup(m_testCtx, "default_framebuffer", "Blits with default framebuffer");
		addChild(defaultFbGroup);

		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
		{
			const deUint32					format		= colorFormats[fmtNdx];
			const tcu::TextureFormat		texFmt		= glu::mapGLInternalFormat(format);
			const tcu::TextureChannelClass	fmtClass	= tcu::getTextureChannelClass(texFmt.type);
			const deUint32					filter		= glu::isGLInternalColorFormatFilterable(format) ? GL_LINEAR : GL_NEAREST;
			const bool						filterable	= glu::isGLInternalColorFormatFilterable(format);

			if (fmtClass != tcu::TEXTURECHANNELCLASS_FLOATING_POINT &&
				fmtClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT &&
				fmtClass != tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT)
				continue; // Conversion not supported.

			defaultFbGroup->addChild(new BlitDefaultFramebufferCase(m_context, getFormatName(format), "", format, filter));

			for (int areaNdx = 0; areaNdx < DE_LENGTH_OF_ARRAY(areas); areaNdx++)
			{
				const string	name				= string(areas[areaNdx].name);
				const bool		addLinear			= filterable;
				const bool		addNearest			= !addLinear || (areas[areaNdx].area != DefaultFramebufferBlitCase::AREA_OUT_OF_BOUNDS); // No need to check out-of-bounds with different filtering

				if (addNearest)
				{
					defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_nearest_" + name + "_blit_from_default").c_str(), "", format, GL_NEAREST, DefaultFramebufferBlitCase::BLIT_DEFAULT_TO_TARGET, areas[areaNdx].area));
					defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_nearest_" + name + "_blit_to_default").c_str(), "", format, GL_NEAREST, DefaultFramebufferBlitCase::BLIT_TO_DEFAULT_FROM_TARGET, areas[areaNdx].area));
				}

				if (addLinear)
				{
					defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_linear_" + name + "_blit_from_default").c_str(), "", format, GL_LINEAR, DefaultFramebufferBlitCase::BLIT_DEFAULT_TO_TARGET, areas[areaNdx].area));
					defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_linear_" + name + "_blit_to_default").c_str(), "", format, GL_LINEAR, DefaultFramebufferBlitCase::BLIT_TO_DEFAULT_FROM_TARGET, areas[areaNdx].area));
				}
			}
		}
	}
}

} // Functional
} // gles3
} // deqp

redpajama_set_name: RedPajamaGithub


The Twist-Lock connector is a product of Hubbell Wiring Device-Kellems. The Twist-Lock connector is used in applications where the connector must stay locked in place, like some computer and medical equipment. The "plug" has curved blades that, once inserted into the receptacle and twisted, can't be pulled from the receptacle unless the plug is twisted in the opposite direction to "unlatch" it. When wiring the plug, you 'll find it has three color-coded terminals, a positive, a neutral and a ground.
Green is for ground, white is for neutral; power is anything else.
Wrap the "hot" wire--usually black, clockwise around the screw in the plug's gold-colored terminal. Tighten the screw with a screwdriver.
Connect the neutral wire, usually white or gray, to the silver terminal, by wrapping it clockwise around the screw in the terminal in the Twist Lock plug. Tighten the screw.
Twist the strands of the the ground wire, usually green or green with a yellow stripe, to form a single thread of wire. Wrap that thread around the screw in green terminal in the plug. Tighten the screw.
What Does Polarized Plug Mean?


Showers, mainly after midnight. Low around 46. Breezy, with a north wind 5 to 10 mph increasing to 15 to 20 mph after midnight. Winds could gust as high as 30 mph. Chance of precipitation is 80%.
A 30 percent chance of showers, mainly before 7am. Mostly sunny, with a high near 69. North northwest wind around 15 mph, with gusts as high as 25 mph.
Partly cloudy, with a low around 40. North northwest wind 5 to 15 mph becoming east after midnight.


The Grandmas Jars Budget Bootcamp 2015 was highly valuable and encouraging experience through which I learned to manage my budget for the first time and be intentional with my finances.
The Bootcamp involved 12 group sessions in which Phil and Teresa guided use through the Grandmas Jars budgeting system. I always left these sessions feeling encouraged, inspired and well-equipped to make positive financial choices.
I came into the Bootcamp with one bank account and no system for keeping track of spending. Moving to a three bank account structure and the Grandmas Jars budgeting system has meant I am more aware of what I am spending money on and what I am saving towards. It gives me a really useful framework for deciding whether and when to buy something, and allows me to be accountable to my values, goals and intentions in how to spend money.
Key components of the system are the Grandmas Jars website which I find quite intuitive, along with the phone app which is particularly useful. The app allows me to easily check the balances in my "jars" and record spending as I go rather than sorting through piles of receipts!
I have been so blessed and encouraged by Phil and Teresa's genuine passion and wisdom – I know the Grandmas Jars Bootcamp has set me in good stead for the future and will continue using this system.


I missed blogging regularly while I was pregnant. Between the exhaustion of the first trimester, preparations in the second, class, and just regular activities in the third I didn't get a chance to post as much as I would have liked. So excuse the off-season post today. I realized that I never delivered on my promise to share our summer vacation eats in more detail.
Our first stop on vacation was Burlington, Vermont for the Vermont Cheesemaker's Festival and other delicious eats. I did manage to post about that (Vacation Eats: Burlington, Vermont)!
After our dairy extravaganza in Vermont we hit the road headed north. Just a few hours later we crossed the bridge and arrived on the island of Montreal. Did you know that it is on an island? We stayed right in the Old City. The location was perfect for squeezing in a lot in a short amount of time.
Before heading to Montreal, I asked food friends for their tips on where to eat. As lovers of a good deli, we knew we wanted to sample the famous Montreal smoked meat and of course the bagels. Thanks to my Canadian friends I met at Eat, Write, Retreat and other food-loving pals we had a three page list of eateries to explore. Thanks to Ethan, Kimmy, Isabelle, Olga, Emily and others who sent along tips!
Our first food stop in town was Schwartz's for smoked meat. In the same location since 1928, it is a fixture in the Montreal food scene. Montreal smoked meat is brisket that has been seasoned, marinated, cured for a week (or more) and then hot smoked. Similar to corned beef or pastrami, but distinctly unique in texture and seasoning. We lined up outside the restaurant and waited for a spot for four at one of the long tables packed into the place. After a short wait, we squeezed into four cozy seats at the back of the energetic space. We ordered up sandwiches, pickles, coleslaw and some Cott's Black Cherry soda per Ethan's advice (and a Canada Dry...since we were in Canada...). The only disappointment is that they had already sold out of half-sour pickles for the day. We managed to get by with the regular kosher dills.
The generous stack of smoked meat was sandwiched between thick cut rye with tangy yellow mustard. It was a perfect sandwich. We were satisfied and sufficiently stuffed for a nice walk over to the Parc du Mont-Royal. From there we walked through McGill University and down Rue St. Catherine and back to Old Montreal. I think we ended up walking about 4 miles - not bad for being four-months pregnant!
The next day we decided to do our Montreal bagel taste test. After all that walking we headed out in the car for our adventure. Montreal is known for bagels that are hand rolled, boiled in honey water, and cooked in a wood fired oven. This gives them the chewy texture and slightly sweet taste. The signature bagel is sesame. From my pre-trip polling I discovered that loyalties are divided when it comes to Montreal bagels. You're either a Fairmont or a St. Viateur. It was an even split between my sources.
Our first stop was The Original Fairmount Bagel Bakery. Claiming to be the first bagel in Montreal (opening up shop in 1919), there were high expectations. We tucked into the small shop lined with bagels from floor to ceiling. Behind the counter bagels were being hand-rolled at a remarkable speed before the cooking process. We ordered a half dozen sesame bagels along with a bagel & cream cheese each.
Our second stop was St-Viateur Bagel. St-Viateur opened up shop in 1957 and has been rolling out hot bagels non-stop! The shop was slightly more spacious, but still just a counter to order and take-away the goods. St-Viateur also has some bakery-cafes in other locations with seating and a more extensive menu. We were there for the bagels. The front window was lined with bags of flour waiting to be mixed, hand-rolled, boiled and baked off in a wood-fired oven. The speed of the hand rolling makes each bagel a unique shape as they are whipped together before the next step in the process. This location offered strictly bagels - packaged cream cheese was in a refrigerator case.
After sampling both, we had a favorite too. Something about the texture (they give your jaw a little workout), the hint of sweetness, the toasted sesame seeds, and the wood-fired crunch made St-Viateur the winner for us. After eating the half we purchased on our first trip we made a stop on our way out of town to stock up on more!
We had a fantastic trip to Montreal and look forward to going back! With such a long list of great places to eat (and see) we need a few more visits. Have you been to Montreal? Where did you eat? And are you a Fairmount or a St-Viateur?
I love Montreal!!! We went to Fairmount. We went late in the day though and we were rushed so we didn't have the greatest experience, unfortunately. I'd love to go back and give it another shot. My favorite favorite place in Montreal though was Patisserie Kouign Ammann. Amaaaazing croissants.
I've never tried Montreal bagels but I've heard so many good things about them!
My favorite two things to eat when in Canada: Poutine and Croque-Monsieurs! I don't have any specific restaurant recommendations in Montreal, but if you ever go to Quebec City (which I recommend in and of itself!), I can't say enough about the food at Pain Beni at the Auberge Place d'Armes (which is worth staying at as well). The prix fixe meal I ate there 7+ years ago stands out to this day as one of the best meals I ever ate!
We love Montreal too! We told the border guard that we had bought a dozen St. Viateur bagels to take home and his quick response was: "so, how many of them do you have left?" uummm, not that many - my husband couldn't resist while they were warm. We were looking for poutine, and a woman who worked at a combat-zone type bar recommended a place - that was pretty awful. Still looking for great poutine everywhere, but we've learned that strippers maybe aren't the best food critics!


Is it possible to get an old external HD and put an OS on it so I can use software/create temp files/store files?
Basically I want to make a "second PC" that I can unplug and lockup in a safe at night. Something I can use bookkeeping software/ photo editing software and have NONE of the files on my pc I'm leaving unattended? Would a large SD card work if I set the pc to boot from it?
Re: The disposable hard drive?
Sure. You can boot from a USB thumb drive, USB flash drive or any other external storage device. You can also buy internal SATA mounts that will let you insert and remove a normal SATA drive so you can lock it up. They come with a tubular locking mechanism that locks the drive into the computer and requires a key to insert or remove.
I don't know if any special care is needed, but some years ago me and my dad shared the same computer. So my OS was on the internal HD, and his was on and External HD. When he wanted to use the computer, just connected it and done.
The only thing is it can't be connected via USB. It needs to be by Firewire or something like that because of the data transfer rate.
Don't really know the details of that but yes, it is possible!
Go ahead, keep plugging away, picking on me! You will end up on bypass or with rigor mortise.
xeo wrote: Sure. You can boot from a USB thumb drive, USB flash drive or any other external storage device. You can also buy internal SATA mounts that will let you insert and remove a normal SATA drive so you can lock it up. They come with a tubular locking mechanism that locks the drive into the computer and requires a key to insert or remove.
You can have a whole OS running through a USB?
fgarci03 wrote: You can have a whole OS running through a USB?
To be honest I tend to use a virtual machine these days rather than booting an alternate one from another drive.
I run linux from a usb thumb drive. Check this link out for software to do it the easy way- http://unetbootin.sourceforge.net . Encrypt the home folder so even if they get your thumb drive it will do them no good. Unless "they" are the NSA you should be alright. I would suggest lubuntu a lighter version of ubuntu for the drive. If you don't want to screw with it you can buy a thumb drive with linux pre-installed on it from ebay. Not sure how many files you plan on storing but, a 64 GB thumb drive is easy to hide and can store a ton of stuff.
Last edited by jruther2 on Thu May 09, 2013 3:51 pm, edited 1 time in total.
If you have little or no experience with Linux I suggest Ubuntu. The nice thing about Ubuntu is that it allows you to set off a section of the hard drive for settings and files so that everytime you boot from USB it is how you left it.
Yes it is possible, as others have mentioned. If you want to keep your data extra secure, you could consider encrypting important data using TrueCrypt. (Or similar software).
It can be set up to hide the encrypted data too, so it is impossible to know that there is encrypted data on there.
I'd caution against using a thumb drive if you're dealing with important files. Those things fall apart in the pocket, get put in with laundry, lose all their data when not removed safely, and sometimes just fail inexplicably. Though it's not as convenient, I'd go with a slim external hard drive.
You could use truecrypt to encrypt the drive but the problem is that you can not boot anything but Windows using a truecrypt volume. Windows can not boot from a USB drive so the only way to do an encrypted OS is to have it as the main HDD in the computer and a USB drive to store the files. What you can do with a USB hard drive and Linux is have the installer make a encrypted LVM as the partition and install to there. You can boot from this because the only thing that is unencrypted is boot section and this does not need to be encrypted to remain secure.
Not true. It's not like it's a *good* operating system, but if the priority is encryption, it'd work.


Published 04/22/2019 10:40:05 pm at 04/22/2019 10:40:05 pm in Duct Tape Dry Erase Board.
duct tape dry erase board dry erase board diy magnetic dry erase kids chore chart grey house harbor diy magentic dry erase board chore chart greyhouseharborcom.
duct tape dry erase board,how to remove duct tape residue from dry erase board,how to make a duct tape dry erase board, asst color fine tip dryerase marker pack mazer wholesale inc jpg, tape king flexible magnetic tape inch x feet thicker and tape king flexible magnetic tape inch x feet thicker and stronger, roll of selfadhesive flexible magnetic tape for diy projects and roll of selfadhesive flexible magnetic tape for diy projects and dry erase boards, how to make a duct tape dry erase board part youtube how to make a duct tape dry erase board part , cute dry erase board for backtoschool mod podge rocks duck tape is one of the easiest craft supplies to use ever you simply pull it off the roll and tape it down it sticks to everything, tesa professional tesa tesa , unique dry erase labels shots harmonartlabcom amazon com houseables dry erase labels magnetic roll magnet, duct tape colored decorative duct tape staples staples acrylic utility duct tape standard grade silver x yds roll cc.


Is It Okay To Ask Questions About Our Christian Faith?
Women Doing Apologetics: Why Women and Why Now?
I just returned from speaking in the Women in Apologetics Conference at Biola in La Mirada, California. What I enjoyed most was interacting with several hundred women who were passionate about learning and sharing the rational reasons for our hope in Jesus Christ. This passion is spreading among Christian women across the nation, and I am so excited to be a part of a this groundbreaking movement.
Even ten years ago the landscape looked quite different. Our first women's apologetics conference at Southern Evangelical Seminary in Charlotte, North Carolina, about seven years ago was among the first apologetics conferences just for women. Since that time, we're seeing women flooding into seminary apologetics programs and about half of our PhD student body at SES is comprised of women.
Some may wonder why we need apologetics conferences just for women. I think it is a legitimate question. The content of apologetics forms a single body of knowledge, so there is no distinct "women's version of apologetics." This body of knowledge is comprised of evidences for objective truth, existence of the theistic God, miracles, biblical reliability, and the deity and atoning work of Jesus Christ, in terms of general categories.
But, here's the point. While the content of apologetics is the same for men and women, the way that women learn this content and deliver it is distinctive. For example, many Christian women avoid apologetics because they see it as a argumentative and academic, with very little connection to their daily lives. Some also believe that the content is just too hard to learn or they cannot bear the thought of adding one more to-do to their already overloaded plate of commitments.
But as more and more women are entering this field of study in seminary and are fulfilling their calling to teach other women, Christian women whose expertise lies in other areas, from homemaking to banking, are hearing these vital apologetics truths in women's voices, with women's relational concerns at the forefront. Because of this, Christian women as a whole are now seeing apologetics as a vital tool they can use to build their own faith as well as to provide somewhere to go in a conversation when their co-worker or college-aged kid asks a question or raises an objection to the claims of Christianity.
It's a long time coming. Our brothers in Christ have paved the way for us. It's not a competition. It's time for us to move alongside them and to encourage each other as women, fulfilling our Titus 2 commission to mentor other women, and specifically to mentor them in understanding and embracing the rational basis for our faith.
Why Do Christian Women Need Apologetics Training?


BE Headwear black knit winter hat with Bluetooth speakers lets you enjoy your music or talk on the phone without hanging wires. It's not too tall, not too tight. This "just right" is perfect from running the mountains to running around town. This is a go-to hat for almost any occasion. Medium weight, it's perfect for fall, winter, and spring. Get your BE Headwear black knit winter hat with Bluetooth speakers from Solid Signal.


text:
PRINCIPAL PHOTOGRAPHY BEGINS ON NEW 'STAR WARS' FILM
Focusing on Han Solo
Posted by ICv2 on February 22, 2017 @ 2:00 am CT
Principal photography on the Han Solo-centered Star Wars Anthology film officially began this week at Pinewood Studios in London.
Phil Lord and Christopher Miller are sharing director duties on the as-yet-unnamed project. On January 30, Miller revealed via Twitter that preliminary filming on "Red Cup" (as in Solo), the working name for the film, was underway (see "'Aquaman,' 'Kong: Skull Island,' 'Han Solo,' 'Avatar'").
The film centers on everyone's favorite smuggler and his Wookie first mate, Chewbacca. Chewie is being played by Finnish basketball player and actor Joonas Suotamo, who stands at 6'11". Suotamo first suited up for the role in The Force Awakens, playing stunt double to the original Chewbacca, Peter Mayhew (Suotamo is a few inches shy of Mayhew's 7'2").
The role of Solo is being played by Alden Ehrenreich (see "Young Han Solo Cast"). Other members of the cast include Donald Glover as Lando Calrissian (see "'Han Solo,' More"), Woody Harrelson as Solo's mentor (see "Woody Harrelson For 'Han Solo' Film"), and Emilia Clarke in an undisclosed role (see "'Black Panther,' 'Han Solo'"). Han Solo opens May 25, 2018.
Marvel Comics has been lining up plenty of Han Solo-related comics to sell. Star Wars: Han Solo by Marjorie Liu and Mark Books (see "Star Wars 'Han Solo' Comic Series Announced") is launching in June. Marvel released the trade paperback collection of the previous Han Solo series in January.