text:
import { IReduxState, IStore } from '../app/types';
import { TILE_VIEW_ENABLED } from '../base/flags/constants';
import { getFeatureFlag } from '../base/flags/functions';
import { pinParticipant } from '../base/participants/actions';
import { getParticipantCount, getPinnedParticipant } from '../base/participants/functions';
import { FakeParticipant } from '../base/participants/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { isStageFilmstripAvailable } from '../filmstrip/functions';
import { isVideoPlaying } from '../shared-video/functions';
import { VIDEO_QUALITY_LEVELS } from '../video-quality/constants';
import { getReceiverVideoQualityLevel } from '../video-quality/functions';
import { getMinHeightForQualityLvlMap } from '../video-quality/selector';

import { LAYOUTS } from './constants';

/**
 * A selector for retrieving the current automatic pinning setting.
 *
 * @private
 * @returns {string|undefined} The string "remote-only" is returned if only
 * remote screen sharing should be automatically pinned, any other truthy value
 * means automatically pin all screen shares. Falsy means do not automatically
 * pin any screen shares.
 */
export function getAutoPinSetting() {
    return typeof interfaceConfig === 'object'
        ? interfaceConfig.AUTO_PIN_LATEST_SCREEN_SHARE
        : 'remote-only';
}

/**
 * Returns the {@code LAYOUTS} constant associated with the layout
 * the application should currently be in.
 *
 * @param {Object} state - The redux state.
 * @returns {string}
 */
export function getCurrentLayout(state: IReduxState) {
    if (navigator.product === 'ReactNative') {
        // FIXME: what should this return?
        return undefined;
    } else if (shouldDisplayTileView(state)) {
        return LAYOUTS.TILE_VIEW;
    } else if (interfaceConfig.VERTICAL_FILMSTRIP) {
        if (isStageFilmstripAvailable(state, 2)) {
            return LAYOUTS.STAGE_FILMSTRIP_VIEW;
        }

        return LAYOUTS.VERTICAL_FILMSTRIP_VIEW;
    }

    return LAYOUTS.HORIZONTAL_FILMSTRIP_VIEW;
}

/**
 * Selector for determining if the UI layout should be in tile view. Tile view
 * is determined by more than just having the tile view setting enabled, as
 * one-on-one calls should not be in tile view, as well as etherpad editing.
 *
 * @param {Object} state - The redux state.
 * @returns {boolean} True if tile view should be displayed.
 */
export function shouldDisplayTileView(state: IReduxState) {
    const { tileViewEnabled } = state['features/video-layout'] ?? {};

    if (tileViewEnabled !== undefined) {
        // If the user explicitly requested a view mode, we
        // do that.
        return tileViewEnabled;
    }

    const tileViewEnabledFeatureFlag = getFeatureFlag(state, TILE_VIEW_ENABLED, true);
    const { disableTileView } = state['features/base/config'];

    if (disableTileView || !tileViewEnabledFeatureFlag) {
        return false;
    }

    const participantCount = getParticipantCount(state);
    const { iAmRecorder } = state['features/base/config'];

    // None tile view mode is easier to calculate (no need for many negations), so we do
    // that and negate it only once.
    const shouldDisplayNormalMode = Boolean(

        // Reasons for normal mode:

        // Editing etherpad
        state['features/etherpad']?.editing

        // We pinned a participant
        || getPinnedParticipant(state)

        // It's a 1-on-1 meeting
        || participantCount < 3

        // There is a shared YouTube video in the meeting
        || isVideoPlaying(state)

        // We want jibri to use stage view by default
        || iAmRecorder
    );

    return !shouldDisplayNormalMode;
}

/**
 * Private helper to automatically pin the latest screen share stream or unpin
 * if there are no more screen share streams.
 *
 * @param {Array<string>} screenShares - Array containing the list of all the screen sharing endpoints
 * before the update was triggered (including the ones that have been removed from redux because of the update).
 * @param {Store} store - The redux store.
 * @returns {void}
 */
export function updateAutoPinnedParticipant(
        screenShares: Array<string>, { dispatch, getState }: IStore) {
    const state = getState();
    const remoteScreenShares = state['features/video-layout'].remoteScreenShares;
    const pinned = getPinnedParticipant(getState);

    // if the pinned participant is shared video or some other fake participant we want to skip auto-pinning
    if (pinned?.fakeParticipant && pinned.fakeParticipant !== FakeParticipant.RemoteScreenShare) {
        return;
    }

    // Unpin the screen share when the screen sharing participant leaves. Switch to tile view if no other
    // participant was pinned before screen share was auto-pinned, pin the previously pinned participant otherwise.
    if (!remoteScreenShares?.length) {
        let participantId = null;

        if (pinned && !screenShares.find(share => share === pinned.id)) {
            participantId = pinned.id;
        }
        dispatch(pinParticipant(participantId));

        return;
    }

    const latestScreenShareParticipantId = remoteScreenShares[remoteScreenShares.length - 1];

    if (latestScreenShareParticipantId) {
        dispatch(pinParticipant(latestScreenShareParticipantId));
    }
}

/**
 * Selector for whether we are currently in tile view.
 *
 * @param {Object} state - The redux state.
 * @returns {boolean}
 */
export function isLayoutTileView(state: IReduxState) {
    return getCurrentLayout(state) === LAYOUTS.TILE_VIEW;
}

/**
 * Returns the video quality for the given height.
 *
 * @param {number|undefined} height - Height of the video container.
 * @returns {number}
 */
function getVideoQualityForHeight(height: number) {
    if (!height) {
        return VIDEO_QUALITY_LEVELS.LOW;
    }
    const levels = Object.values(VIDEO_QUALITY_LEVELS)
        .map(Number)
        .sort((a, b) => a - b);

    for (const level of levels) {
        if (height <= level) {
            return level;
        }
    }

    return VIDEO_QUALITY_LEVELS.ULTRA;
}

/**
 * Returns the video quality level for the resizable filmstrip thumbnail height.
 *
 * @param {number} height - The height of the thumbnail.
 * @param {Object} state - Redux state.
 * @returns {number}
 */
export function getVideoQualityForResizableFilmstripThumbnails(height: number, state: IReduxState) {
    if (!height) {
        return VIDEO_QUALITY_LEVELS.LOW;
    }

    return getReceiverVideoQualityLevel(height, getMinHeightForQualityLvlMap(state));
}

/**
 * Returns the video quality level for the screen sharing filmstrip thumbnail height.
 *
 * @param {number} height - The height of the thumbnail.
 * @param {Object} state - Redux state.
 * @returns {number}
 */
export function getVideoQualityForScreenSharingFilmstrip(height: number, state: IReduxState) {
    if (!height) {
        return VIDEO_QUALITY_LEVELS.LOW;
    }

    return getReceiverVideoQualityLevel(height, getMinHeightForQualityLvlMap(state));
}

/**
 * Returns the video quality for the large video.
 *
 * @param {number} largeVideoHeight - The height of the large video.
 * @returns {number} - The video quality for the large video.
 */
export function getVideoQualityForLargeVideo(largeVideoHeight: number) {
    return getVideoQualityForHeight(largeVideoHeight);
}

/**
 * Returns the video quality level for the thumbnails in the stage filmstrip.
 *
 * @param {number} height - The height of the thumbnails.
 * @param {Object} state - Redux state.
 * @returns {number}
 */
export function getVideoQualityForStageThumbnails(height: number, state: IReduxState) {
    if (!height) {
        return VIDEO_QUALITY_LEVELS.LOW;
    }

    return getReceiverVideoQualityLevel(height, getMinHeightForQualityLvlMap(state));
}


text:
FROM ubuntu:latest

MAINTAINER Paul Johnson <paul@pjcj.net>

ENV TERM xterm

RUN apt-get update && apt-get -y install wget build-essential

WORKDIR /usr/local/src
RUN wget http://www.cpan.org/src/5.0/perl-5.22.3.tar.gz -O - | tar xzf -
RUN cd perl-5.22.3 && ./Configure -des && make install

redpajama_set_name: RedPajamaGithub


text:
java^
 -Xms64m^
 -Xmx3072m^
 -XX:CompileCommand=exclude,javax/swing/text/GlyphView,getBreakSpot^
 -XX:-OmitStackTraceInFastThrow^
 -jar sw.jar


text:
//
//  PeopleGoalManagerVC.m
//  bluebao
//
//  Created by boye_mac1 on 15/7/31.
//  Copyright (c) 2015年 Boye. All rights reserved.
//

#import "PeopleGoalManagerVC.h"

@interface PeopleGoalManagerVC ()

@end

@implementation PeopleGoalManagerVC

- (void)viewDidLoad {
    [super viewDidLoad];

    self.title = @"我的目标管理";
    self.navigationController.navigationBarHidden = NO;

    self.goalTableView.height = self.goalTableView.height + TABBAR_HEIGHT;

}

-(void)viewWillDisappear:(BOOL)animated{

    [super viewWillDisappear:YES];
    self.goalTableView.height = self.goalTableView.height - TABBAR_HEIGHT;
}

-(void)_initNavs{

    UIButton * leftBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    leftBtn.bounds = CGRectMake(0, 0, 12, 22.5);
    [leftBtn setBackgroundImage:[UIImage imageNamed:@"back.png"] forState:UIControlStateNormal];
    [leftBtn addTarget:self action:@selector(backClick) forControlEvents:UIControlEventTouchUpInside];
    leftBtn.tag = 1;
    UIBarButtonItem* letfItem = [[UIBarButtonItem alloc] initWithCustomView:leftBtn];
    self.navigationItem.leftBarButtonItem = letfItem;
}

#pragma mark --返回 --
-(void)backClick{

    [self.navigationController popViewControllerAnimated:YES];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end


text:
'use strict';

module.exports = {
  up: function (queryInterface, Sequelize) {
    queryInterface.createTable(
      'mig_table',
      {
        id: {
          type: Sequelize.INTEGER,
          primaryKey: true,
          autoIncrement: true
        },
        createdAt: {
          type: Sequelize.DATE
        },
        updatedAt: {
          type: Sequelize.DATE
        },
        attr1: Sequelize.STRING,
        attr2: Sequelize.INTEGER,
        attr3: {
          type: Sequelize.BOOLEAN,
          defaultValue: false,
          allowNull: false
        },
      },
      {
        charset: 'latin1',                    // default: null
      }
    )
  },

  down: function (queryInterface, Sequelize) {
    queryInterface.dropTable('mig_table')
  }
};


text:
{# Displayed when address cannot be found for participant one. #}
{% extends "halfwayapp/base.html" %} {% block content %} {% load staticfiles %}

Sorry, we couldn't match this address.

{{suggestion}}

Please try again

		Return to the homepage

{% endblock %}


text:
/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.activiti.engine.impl.persistence.entity;

import java.io.Serializable;

import org.activiti.engine.impl.context.Context;

/**
 *

 * Encapsulates the logic for transparently working with {@link ByteArrayEntity}.
 *

 *
 *

 * Make sure that instance variables (i.e. fields) of this type are always initialized, and thus never null.
 *

 *
 *

 * For example:
 *

 *
 *

 * private final ByteArrayRef byteArrayRef = new ByteArrayRef();
 *

 *
 * @author Marcus Klimstra (CGI)
 */
public final class ByteArrayRef implements Serializable {

    private static final long serialVersionUID = 1L;

    private String id;
    private String name;
    private ByteArrayEntity entity;
    protected boolean deleted;

    public ByteArrayRef() {
    }

    // Only intended to be used by ByteArrayRefTypeHandler
    public ByteArrayRef(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public byte[] getBytes() {
        ensureInitialized();
        return (entity != null ? entity.getBytes() : null);
    }

    public void setValue(String name, byte[] bytes) {
        this.name = name;
        setBytes(bytes);
    }

    private void setBytes(byte[] bytes) {
        if (id == null) {
            if (bytes != null) {
                entity = ByteArrayEntity.createAndInsert(name, bytes);
                id = entity.getId();
            }
        } else {
            ensureInitialized();
            entity.setBytes(bytes);
        }
    }

    public ByteArrayEntity getEntity() {
        ensureInitialized();
        return entity;
    }

    public void delete() {
        if (!deleted && id != null) {
            if (entity != null) {
                // if the entity has been loaded already,
                // we might as well use the safer optimistic locking delete.
                Context.getCommandContext()
                        .getByteArrayEntityManager()
                        .deleteByteArray(entity);
            } else {
                Context.getCommandContext()
                        .getByteArrayEntityManager()
                        .deleteByteArrayById(id);
            }
            entity = null;
            id = null;
            deleted = true;
        }
    }

    private void ensureInitialized() {
        if (id != null && entity == null) {
            entity = Context.getCommandContext()
                    .getByteArrayEntityManager()
                    .findById(id);
            name = entity.getName();
        }
    }

    public boolean isDeleted() {
        return deleted;
    }

    @Override
    public String toString() {
        return "ByteArrayRef[id=" + id + ", name=" + name + ", entity=" + entity + (deleted ? ", deleted]" : "]");
    }
}


text:
#include "picrin.h"
#include "picrin/extra.h"
#include "picrin/private/object.h"
#include "picrin/private/state.h"

void
pic_panic(pic_state *pic, const char *msg)
{
  if (pic->panicf) {
    pic->panicf(pic, msg);
  }

#if PIC_USE_STDIO
  fprintf(stderr, "picrin panic!: %s\n", msg);
#endif

  PIC_ABORT(pic);

  PIC_UNREACHABLE();
}

void
pic_warnf(pic_state *pic, const char *fmt, ...)
{
  va_list ap;
  pic_value err;

  va_start(ap, fmt);
  err = pic_vstrf_value(pic, fmt, ap);
  va_end(ap);

  pic_fprintf(pic, pic_stderr(pic), "warn: %s\n", pic_str(pic, err));
}

static pic_value
native_exception_handler(pic_state *pic)
{
  pic_value err;

  pic_get_args(pic, "o", &err);

  pic->err = err;

  pic_call(pic, pic_closure_ref(pic, 0), 1, pic_false_value(pic));

  PIC_UNREACHABLE();
}

static pic_value
dynamic_set(pic_state *pic)
{
  pic_value var, val;

  pic_get_args(pic, "");

  var = pic_closure_ref(pic, 0);
  val = pic_closure_ref(pic, 1);

  pic_proc_ptr(pic, var)->locals[0] = val;

  return pic_undef_value(pic);
}

pic_value
pic_start_try(pic_state *pic, PIC_JMPBUF *jmp)
{
  struct cont *cont;
  pic_value handler;
  pic_value var, old_val, new_val;
  pic_value in, out;
  struct checkpoint *here;

  /* call/cc */

  cont = pic_alloca_cont(pic);
  pic_save_point(pic, cont, jmp);
  handler = pic_lambda(pic, native_exception_handler, 1, pic_make_cont(pic, cont));

  /* with-exception-handler */

  var = pic_ref(pic, "picrin.base", "current-exception-handlers");
  old_val = pic_call(pic, var, 0);
  new_val = pic_cons(pic, handler, old_val);

  in = pic_lambda(pic, dynamic_set, 2, var, new_val);
  out = pic_lambda(pic, dynamic_set, 2, var, old_val);

  /* dynamic-wind */

  pic_call(pic, in, 0);       /* enter */

  here = pic->cp;
  pic->cp = (struct checkpoint *)pic_obj_alloc(pic, sizeof(struct checkpoint), PIC_TYPE_CP);
  pic->cp->prev = here;
  pic->cp->depth = here->depth + 1;
  pic->cp->in = pic_proc_ptr(pic, in);
  pic->cp->out = pic_proc_ptr(pic, out);

  return pic_cons(pic, pic_obj_value(here), out);
}

void
pic_end_try(pic_state *pic, pic_value cookie)
{
  struct checkpoint *here = (struct checkpoint *)pic_obj_ptr(pic_car(pic, cookie));
  pic_value out = pic_cdr(pic, cookie);

  pic->cp = here;

  pic_call(pic, out, 0); /* exit */

  pic_exit_point(pic);
}

pic_value
pic_err(pic_state *pic)
{
  return pic->err;
}

pic_value
pic_make_error(pic_state *pic, const char *type, const char *msg, pic_value irrs)
{
  struct error *e;
  pic_value stack, ty = pic_intern_cstr(pic, type);

  stack = pic_get_backtrace(pic);

  e = (struct error *)pic_obj_alloc(pic, sizeof(struct error), PIC_TYPE_ERROR);
  e->type = pic_sym_ptr(pic, ty);
  e->msg = pic_str_ptr(pic, pic_cstr_value(pic, msg));
  e->irrs = irrs;
  e->stack = pic_str_ptr(pic, stack);

  return pic_obj_value(e);
}

pic_value pic_raise_continuable(pic_state *, pic_value err);

void
pic_error(pic_state *pic, const char *msg, int n, ...)
{
  va_list ap;
  pic_value irrs;

  va_start(ap, n);
  irrs = pic_vlist(pic, n, ap);
  va_end(ap);

  pic_raise(pic, pic_make_error(pic, "", msg, irrs));
}

static pic_value
raise(pic_state *pic)
{
  pic_get_args(pic, "");

  pic_call(pic, pic_closure_ref(pic, 0), 1, pic_closure_ref(pic, 1));

  pic_error(pic, "handler returned", 2, pic_closure_ref(pic, 0), pic_closure_ref(pic, 1));
}

void
pic_raise(pic_state *pic, pic_value err)
{
  pic_value stack, exc = pic_ref(pic, "picrin.base", "current-exception-handlers");

  stack = pic_call(pic, exc, 0);

  if (pic_nil_p(pic, stack)) {
    pic_panic(pic, "no exception handler");
  }

  pic_dynamic_bind(pic, exc, pic_cdr(pic, stack), pic_lambda(pic, raise, 2, pic_car(pic, stack), err));

  PIC_UNREACHABLE();
}

static pic_value
raise_continuable(pic_state *pic)
{
  pic_get_args(pic, "");

  return pic_call(pic, pic_closure_ref(pic, 0), 1, pic_closure_ref(pic, 1));
}

pic_value
pic_raise_continuable(pic_state *pic, pic_value err)
{
  pic_value stack, exc = pic_ref(pic, "picrin.base", "current-exception-handlers");

  stack = pic_call(pic, exc, 0);

  if (pic_nil_p(pic, stack)) {
    pic_panic(pic, "no exception handler");
  }

  return pic_dynamic_bind(pic, exc, pic_cdr(pic, stack), pic_lambda(pic, raise_continuable, 2, pic_car(pic, stack), err));
}

static pic_value
pic_error_with_exception_handler(pic_state *pic)
{
  pic_value handler, thunk;
  pic_value stack, exc = pic_ref(pic, "picrin.base", "current-exception-handlers");

  pic_get_args(pic, "ll", &handler, &thunk);

  stack = pic_call(pic, exc, 0);

  return pic_dynamic_bind(pic, exc, pic_cons(pic, handler, stack), thunk);
}

static pic_value
pic_error_raise(pic_state *pic)
{
  pic_value v;

  pic_get_args(pic, "o", &v);

  pic_raise(pic, v);
}

static pic_value
pic_error_raise_continuable(pic_state *pic)
{
  pic_value v;

  pic_get_args(pic, "o", &v);

  return pic_raise_continuable(pic, v);
}

static pic_value
pic_error_error(pic_state *pic)
{
  const char *str;
  int argc;
  pic_value *argv;

  pic_get_args(pic, "z*", &str, &argc, &argv);

  pic_raise(pic, pic_make_error(pic, "", str, pic_make_list(pic, argc, argv)));
}

static pic_value
pic_error_error_object_p(pic_state *pic)
{
  pic_value v;

  pic_get_args(pic, "o", &v);

  return pic_bool_value(pic, pic_error_p(pic, v));
}

static pic_value
pic_error_error_object_message(pic_state *pic)
{
  pic_value e;

  pic_get_args(pic, "o", &e);

  TYPE_CHECK(pic, e, error);

  return pic_obj_value(pic_error_ptr(pic, e)->msg);
}

static pic_value
pic_error_error_object_irritants(pic_state *pic)
{
  pic_value e;

  pic_get_args(pic, "o", &e);

  TYPE_CHECK(pic, e, error);

  return pic_error_ptr(pic, e)->irrs;
}

static pic_value
pic_error_error_object_type(pic_state *pic)
{
  pic_value e;

  pic_get_args(pic, "o", &e);

  TYPE_CHECK(pic, e, error);

  return pic_obj_value(pic_error_ptr(pic, e)->type);
}

void
pic_init_error(pic_state *pic)
{
  pic_defvar(pic, "current-exception-handlers", pic_nil_value(pic), pic_false_value(pic));
  pic_defun(pic, "with-exception-handler", pic_error_with_exception_handler);
  pic_defun(pic, "raise", pic_error_raise);
  pic_defun(pic, "raise-continuable", pic_error_raise_continuable);
  pic_defun(pic, "error", pic_error_error);
  pic_defun(pic, "error-object?", pic_error_error_object_p);
  pic_defun(pic, "error-object-message", pic_error_error_object_message);
  pic_defun(pic, "error-object-irritants", pic_error_error_object_irritants);
  pic_defun(pic, "error-object-type", pic_error_error_object_type);
}


text:
package openmods.serializable.cls;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SerializableClass {

}


text:
use strict;
use warnings;

use Net::GitHub;
use Getopt::Long;
our ($progname) = $0 =~ m#(?:.*/)?([^/]*)#;

my $org  = '';
my $repo = '';
my $username = '';
my $password = '';
my $is_output_token_only = 0;
my $token = '';
my $labels = '';
my $is_verbose = 0;
my $is_show_current_labels_only = 0;

sub show_usage {
    print STDERR "Error: $_[0]" . "\n\n";

    print STDERR "Usage:\n";
    print STDERR "- Access directly with github username and password\n";
    print STDERR "  $progname --org=g0v --repo=hack.g0v.tw --username=github_user --password=github_password --labels='bug|FFFFFF,important|DF0101'\n";
    print STDERR "- Access by token\n";
    print STDERR "  $progname --output-token-only --username=github_user --password=github_password > tokenfile\n";
    print STDERR "  $progname --token=`cat ./tokenfile` --org=g0v --repo=hack.g0v.tw --labels='bug|FFFFFF,important|DF0101'\n";
    print STDERR "  $progname --token=`cat ./tokenfile` --org=g0v --repo=dev --labels='bug|FFFFFF,important|DF0101'\n";
    print STDERR "- All options:\n";
    print STDERR "  --org      <string>|-o     Organization/User\n";
    print STDERR "  --repo     <string>|-r     Repository\n";
    print STDERR "  --labels   <string>|-l     Label string, format: 'name1|color1,name2|color2,...'\n";
    print STDERR "  --username <string>|-u     Github username\n";
    print STDERR "  --password <string>|-p     Github password\n";
    print STDERR "  --token    <string>|-t     Github access token\n";
    print STDERR "  --verbose          |-v     Verbose\n";
    print STDERR "  --show-current-labels      Show current labels of specific repository and quit\n";
    print STDERR "  --output-token-only        Ouput access token to STDOUT and quit\n";

    exit($_[1]);
}

GetOptions(
    'org|o=s'      => \$org,
    'repo|r=s'     => \$repo,
    'username|u=s' => \$username,
    'password|p=s' => \$password,
    'output-token-only' => \$is_output_token_only,
    'token|t=s'    => \$token,
    'labels|l=s'   => \$labels,
    'verbose|v'    => \$is_verbose,
    'show-current-labels' => \$is_show_current_labels_only,
) or show_usage('Incorrect options.', 1);

# $org and $repo are required.
if (!$is_output_token_only) {
    show_usage("Missing --org {Your org/user}", 1) unless $org;
    show_usage("Missing --repo", 1) unless $repo;
}

my $github_token;
my $oauth;
my $oauth_result;
# When not giving token, $username and $password are required.
if (!$token) {
    show_usage("Github username not set", 1) unless $username;
    show_usage("Github password not set", 1) unless $password;

    $github_token = Net::GitHub::V3->new( login => $username, pass => $password );
    $oauth = $github_token->oauth;
    $oauth_result = $oauth->create_authorization( {
            scopes => ['public_repo'], # just ['public_repo']
            note   => 'Create labels',
            } );

    if ($is_output_token_only) {
        # output token and quit.
        print $oauth_result->{token};
        exit 0;
    }
}

my $github;
if ($token) {
    $github = Net::GitHub->new(
        access_token => $token
    );
} else {
    $github = Net::GitHub->new(
        access_token => $oauth_result->{token}
    );
}

$github->set_default_user_repo($org, $repo);

my $issue = $github->issue;
my @current_labels = $issue->labels;

my @labels_to_update_tmp = split(/,/, $labels);
my @labels_to_update;

foreach (@labels_to_update_tmp) {
    my @each_label = split(/\|/, $_);
    my $name = $each_label[0];
    my $color = $each_label[1];
    my %tmp_hash = ("name" => $name, "color" => $color);
    push @labels_to_update, \%tmp_hash;
}

my %label_update_res;
my %label_create_res;
my $label_color;
my $label_name;
my $action;

#foreach (@labels_to_update) {
#        print "@{[ $_ ]}\n";
#}

if ($is_verbose || $is_show_current_labels_only) {
    # print original labels.
    print STDERR "Original labels for org:$org repo:$repo:\n";
    foreach (@current_labels) {
        print STDERR ' name:' . $_->{name} . ', color:' . $_->{color} . "\n";
    }
}

exit 0 if $is_show_current_labels_only;

foreach (@labels_to_update) {
    $label_name = $_->{name};
    $label_color = $_->{color};
    $action = 'create';

    # find if the label name already exists in repo.
    foreach (@current_labels) {
        if ($_->{name} eq $label_name) {
            $action = 'update';
            last;
        }
    }

    if ( $action eq 'update' ) {
        # update
        print STDERR 'Updating label ' . $label_name . '...';
        %label_update_res  = $issue->update_label( $label_name, {
                "color" => $label_color
                } );
        print STDERR "\n";
        print STDERR "@{[ %label_update_res ]}\n" if $is_verbose;

    } else {
        # create
        print STDERR 'Creating label ' . $label_name . '...';
        %label_create_res = $issue->create_label( {
                "name" => $label_name,
                "color" => $label_color
            } );
        print STDERR "\n";
        print STDERR "@{[ %label_create_res ]}\n" if $is_verbose;
    }
}

0;


text:
using System.Runtime.CompilerServices;
namespace CurlyBraceParser
{
    //public interface ICanBePublicStatement
    //{
    //    bool Public { get; set; }
    //}

    public static class CanBePublicStatementCode
    {
        // provided methods go here, as extension methods to MNamed

        // to maintain state:
        private class State
        {
            // public fields or properties for the desired state
            public string StatementWithoutPublicKeyWord;
            public bool? IsPublic;
        }
        //private static readonly ConditionalWeakTable<LiveStatement, State>
        //  _stateTable = new ConditionalWeakTable<LiveStatement, State>();

        // to access the state:
        public static string GetStatementWithoutPublicKeyWord(this ILiveStatement self)
        {
            //return _stateTable.GetOrCreateValue(self as LiveStatement).StatementWithoutPublicKeyWord;
            if (self.FrontTrimmedLiveStatement.StartsWith(TypeStrictInterpreter.PublicKeyword))
            {

                string start = self.FrontTrimmedLiveStatement.Substring(TypeStrictInterpreter.PublicKeyword.Length).TrimStart();
                return start;
                //self.SetStatementWithoutPublicKeyWord(start);
                //self.SetStatementIsPublic(true);
            }
            else
            {
                return self.FrontTrimmedLiveStatement;
                //self.SetStatementIsPublic(false);
            }
        }
        //public static void SetStatementWithoutPublicKeyWord(this ILiveStatement self, string value)
        //{
        //    _stateTable.GetOrCreateValue(self as LiveStatement).StatementWithoutPublicKeyWord = value;
        //}

        public static bool GetStatementIsPublic(this ILiveStatement self)
        {
            //var ls = self as ILiveStatement;
            //var statement = self as Statement;
            if (self == null || string.IsNullOrEmpty(self.Statement)) return false;
            //if (_stateTable.GetOrCreateValue(self as LiveStatement).IsPublic == null)
            {
                if (self.FrontTrimmedLiveStatement.StartsWith(TypeStrictInterpreter.PublicKeyword))
                {

                    string start = self.FrontTrimmedLiveStatement.Substring(TypeStrictInterpreter.PublicKeyword.Length).TrimStart();
                    return true;
                    //self.SetStatementWithoutPublicKeyWord(start);
                    //self.SetStatementIsPublic(true);
                }
                else
                {
                    return false;
                    //self.SetStatementIsPublic(false);
                }
            }
            //return (bool)_stateTable.GetOrCreateValue(self as LiveStatement).IsPublic;
        }

        //public static void SetStatementIsPublic(this ILiveStatement self, bool value)
        //{
        //    _stateTable.GetOrCreateValue(self as LiveStatement).IsPublic = value;
        //}
    }
}


text:
package com.google.android.perftesting.common;

import android.content.Context;
import android.support.test.InstrumentationRegistry;

import java.io.File;

/**
 * Centralized methods to ensure tests perform certain actions in the same manner.
 */
public class PerfTestingUtils {
    /**
     * Retrieve the directory where test files should be written to.
     * This directory is local to the application and removed when the app is uninstalled.
     */
    public static File getTestDir(String className, String testName) {

        File rootDir = getAppContext().getFilesDir();

        // Create a test data subdirectory.
        File testFileDir = new File(rootDir, "testdata");
        if (getTranslatedTestName(className, testName) != null) {
            testFileDir = new File(testFileDir, getTranslatedTestName(className, testName));
        }

        if (!testFileDir.exists()) {
            if (!testFileDir.mkdirs()) {
                throw new RuntimeException("Unable to create test file directory.");
            }
        }
        return testFileDir;

    }

    /**
     * Retrieve the app-under-test's {@code Context}.
     */
    public static Context getAppContext() {
        return InstrumentationRegistry.getInstrumentation().getTargetContext();
    }

    /**
     * Retrieve a file handle that is within the testing directory where tests should be written to.
     */
    public static File getTestRunFile(String filename) {
        return new File(getTestDir(null, null), filename);
    }

    /**
     * Retrieve the test run directory where tests should be written to.
     */
    public static File getTestRunDir() {
        return getTestDir(null, null);
    }

    private static String getTranslatedTestName(String className, String testName) {
        if (className == null || testName == null) {
            return null;
        }
        String base = className + "_" + testName;

        // Shorten the common strings so "com.google.android" comes out as "c.g.a" for brevity.
        base = base.replace("com", "c")
                   .replace("google", "g")
                   .replace("android", "a")
                   .replace("perfmatters", "pm")
                   .replace("automatingperformancetesting", "apt");
        return base;

    }

    /**
     * Retrieve a file handle that is within the testing directory where tests should be written to.
     */
    public static File getTestFile(String className, String testName, String filename) {
        return new File(getTestDir(className, testName), filename);
    }
}


text:
#include "include/log.h"
#include "include/vk_conv.h"
#include "include/vk_device.h"
#include "include/vk_graphics_pipeline.h"
#include "include/vk_graphics_pipeline_library.h"
#include "include/vk_instance.h"
#include "include/vk_memory.h"
#include "include/vk_pipeline_cache.h"
#include "include/vk_pipeline_layout.h"
#include "include/vk_render_pass.h"
#include "include/vk_shader.h"
#include "include/vk_cmdbuffer.h"

#include "palAutoBuffer.h"
#include "palCmdBuffer.h"
#include "palDevice.h"
#include "palPipeline.h"
#include "palInlineFuncs.h"
#include "palMetroHash.h"

#include <float.h>
#include <math.h>

using namespace Util;

namespace vk
{

// =====================================================================================================================
// Create graphics pipeline binaries
VkResult GraphicsPipeline::CreatePipelineBinaries(
    Device*                                        pDevice,
    const VkGraphicsPipelineCreateInfo*            pCreateInfo,
    const GraphicsPipelineShaderStageInfo*         pShaderInfo,
    const PipelineLayout*                          pPipelineLayout,
    GraphicsPipelineBinaryCreateInfo*              pBinaryCreateInfo,
    PipelineCache*                                 pPipelineCache,
    const VkPipelineCreationFeedbackCreateInfoEXT* pCreationFeedbackInfo,
    Util::MetroHash::Hash*                         pCacheIds,
    size_t*                                        pPipelineBinarySizes,
    const void**                                   pPipelineBinaries)
{
    VkResult          result = VK_SUCCESS;
    const uint32_t    numPalDevices = pDevice->NumPalDevices();
    PipelineCompiler* pDefaultCompiler = pDevice->GetCompiler(DefaultDeviceIndex);

    for (uint32_t i = 0; (result == VK_SUCCESS) && (i < numPalDevices)
         ; ++i)
    {
        if ((i == DefaultDeviceIndex) || (pCreateInfo == nullptr))
        {
            result = pDevice->GetCompiler(i)->CreateGraphicsPipelineBinary(
                pDevice,
                i,
                pPipelineCache,
                pBinaryCreateInfo,
                &pPipelineBinarySizes[i],
                &pPipelineBinaries[i],
                &pCacheIds[i]);
        }
        else
        {
            GraphicsPipelineBinaryCreateInfo binaryCreateInfoMGPU = {};
            VbBindingInfo vbInfoMGPU = {};
            PipelineInternalBufferInfo internalBufferInfoMGPU = {};
            pDefaultCompiler->ConvertGraphicsPipelineInfo(
                pDevice, pCreateInfo, pShaderInfo, pPipelineLayout, &binaryCreateInfoMGPU, &vbInfoMGPU, &internalBufferInfoMGPU);

            result = pDevice->GetCompiler(i)->CreateGraphicsPipelineBinary(
                pDevice,
                i,
                pPipelineCache,
                &binaryCreateInfoMGPU,
                &pPipelineBinarySizes[i],
                &pPipelineBinaries[i],
                &pCacheIds[i]);

            if (result == VK_SUCCESS)
            {
                pDefaultCompiler->SetPipelineCreationFeedbackInfo(
                    pCreationFeedbackInfo,
                    pCreateInfo->stageCount,
                    pCreateInfo->pStages,
                    &binaryCreateInfoMGPU.pipelineFeedback,
                    binaryCreateInfoMGPU.stageFeedback);
            }

            pDefaultCompiler->FreeGraphicsPipelineCreateInfo(&binaryCreateInfoMGPU, false);
        }
    }

    return result;
}

// =====================================================================================================================
// Creates graphics PAL pipeline objects
VkResult GraphicsPipeline::CreatePalPipelineObjects(
    Device*                           pDevice,
    PipelineCache*                    pPipelineCache,
    GraphicsPipelineObjectCreateInfo* pObjectCreateInfo,
    const size_t*                     pPipelineBinarySizes,
    const void**                      pPipelineBinaries,
    const Util::MetroHash::Hash*      pCacheIds,
    void*                             pSystemMem,
    Pal::IPipeline**                  pPalPipeline)
{
    size_t palSize = 0;

    pObjectCreateInfo->pipeline.pipelineBinarySize = pPipelineBinarySizes[DefaultDeviceIndex];
    pObjectCreateInfo->pipeline.pPipelineBinary = pPipelineBinaries[DefaultDeviceIndex];

    Pal::Result palResult = Pal::Result::Success;
    palSize =
        pDevice->PalDevice(DefaultDeviceIndex)->GetGraphicsPipelineSize(pObjectCreateInfo->pipeline, &palResult);
    VK_ASSERT(palResult == Pal::Result::Success);

    RenderStateCache* pRSCache      = pDevice->GetRenderStateCache();
    const uint32_t    numPalDevices = pDevice->NumPalDevices();
    size_t            palOffset     = 0;

    for (uint32_t deviceIdx = 0; deviceIdx < numPalDevices; deviceIdx++)
    {
        Pal::IDevice* pPalDevice = pDevice->PalDevice(deviceIdx);

        if (palResult == Pal::Result::Success)
        {
            // If pPipelineBinaries[DefaultDeviceIndex] is sufficient for all devices, the other pipeline binaries
            // won't be created.  Otherwise, like if gl_DeviceIndex is used, they will be.
            if (pPipelineBinaries[deviceIdx] != nullptr)
            {
                pObjectCreateInfo->pipeline.pipelineBinarySize = pPipelineBinarySizes[deviceIdx];
                pObjectCreateInfo->pipeline.pPipelineBinary = pPipelineBinaries[deviceIdx];
            }

            palResult = pPalDevice->CreateGraphicsPipeline(
                pObjectCreateInfo->pipeline,
                Util::VoidPtrInc(pSystemMem, palOffset),
                &pPalPipeline[deviceIdx]);

#if ICD_GPUOPEN_DEVMODE_BUILD
            // Temporarily reinject post Pal pipeline creation (when the internal pipeline hash is available).
            // The reinjection cache layer can be linked back into the pipeline cache chain once the
            // Vulkan pipeline cache key can be stored (and read back) inside the ELF as metadata.
            if ((pDevice->VkInstance()->GetDevModeMgr() != nullptr) &&
                (palResult == Util::Result::Success))
            {
                const auto& info = pPalPipeline[deviceIdx]->GetInfo();

                palResult = pDevice->GetCompiler(deviceIdx)->RegisterAndLoadReinjectionBinary(
                    &info.internalPipelineHash,
                    &pCacheIds[deviceIdx],
                    &pObjectCreateInfo->pipeline.pipelineBinarySize,
                    &pObjectCreateInfo->pipeline.pPipelineBinary,
                    pPipelineCache);

                if (palResult == Util::Result::Success)
                {
                    pPalPipeline[deviceIdx]->Destroy();

                    palResult = pPalDevice->CreateGraphicsPipeline(
                        pObjectCreateInfo->pipeline,
                        Util::VoidPtrInc(pSystemMem, palOffset),
                        &pPalPipeline[deviceIdx]);
                }
                else if (palResult == Util::Result::NotFound)
                {
                    // If a replacement was not found, proceed with the original
                    palResult = Util::Result::Success;
                }
            }
#endif

            VK_ASSERT(palSize == pPalDevice->GetGraphicsPipelineSize(pObjectCreateInfo->pipeline, nullptr));
            palOffset += palSize;
        }
    }

    return PalToVkResult(palResult);
}

// =====================================================================================================================
// Create graphics pipeline objects
VkResult GraphicsPipeline::CreatePipelineObjects(
    Device*                             pDevice,
    const VkGraphicsPipelineCreateInfo* pCreateInfo,
    const VkAllocationCallbacks*        pAllocator,
    const PipelineLayout*               pPipelineLayout,
    const VbBindingInfo*                pVbInfo,
    const PipelineInternalBufferInfo*   pInternalBuffer,
    const size_t*                       pPipelineBinarySizes,
    const void**                        pPipelineBinaries,
    PipelineCache*                      pPipelineCache,
    const Util::MetroHash::Hash*        pCacheIds,
    GraphicsPipelineObjectCreateInfo*   pObjectCreateInfo,
    VkPipeline*                         pPipeline)
{
    VkResult          result        = VK_SUCCESS;
    Pal::Result       palResult     = Pal::Result::Success;
    const uint32_t    numPalDevices = pDevice->NumPalDevices();
    uint64_t          apiPsoHash    = 0;
    Util::MetroHash64 palPipelineHasher;

    apiPsoHash = BuildApiHash(pCreateInfo, pObjectCreateInfo);
    palPipelineHasher.Update(pObjectCreateInfo->pipeline);

    // Create the PAL pipeline object.
    Pal::IPipeline*          pPalPipeline[MaxPalDevices]     = {};
    Pal::IMsaaState*         pPalMsaa[MaxPalDevices]         = {};
    Pal::IColorBlendState*   pPalColorBlend[MaxPalDevices]   = {};
    Pal::IDepthStencilState* pPalDepthStencil[MaxPalDevices] = {};

    // Get the pipeline size from PAL and allocate memory.
    void*  pSystemMem = nullptr;
    size_t palSize    = 0;

    palSize =
        pDevice->PalDevice(DefaultDeviceIndex)->GetGraphicsPipelineSize(pObjectCreateInfo->pipeline, &palResult);
    VK_ASSERT(palResult == Pal::Result::Success);

    pSystemMem = pDevice->AllocApiObject(
        pAllocator,
        sizeof(GraphicsPipeline) + (palSize * numPalDevices) + pInternalBuffer->dataSize);

    if (pSystemMem == nullptr)
    {
        result = VK_ERROR_OUT_OF_HOST_MEMORY;
    }

    RenderStateCache* pRSCache = pDevice->GetRenderStateCache();

    if (result == VK_SUCCESS)
    {
        result = CreatePalPipelineObjects(pDevice,
            pPipelineCache,
            pObjectCreateInfo,
            pPipelineBinarySizes,
            pPipelineBinaries,
            pCacheIds,
            Util::VoidPtrInc(pSystemMem, sizeof(GraphicsPipeline)),
            pPalPipeline);
    }

    if (result == VK_SUCCESS)
    {
        for (uint32_t deviceIdx = 0; deviceIdx < numPalDevices; deviceIdx++)
        {
            Pal::IDevice* pPalDevice = pDevice->PalDevice(deviceIdx);

            // Create the PAL MSAA state object
            if (palResult == Pal::Result::Success)
            {
                // Force full sample shading if the app didn't enable it, but the shader wants
                // per-sample shading by the use of SampleId or similar features.
                if ((pObjectCreateInfo->immedInfo.rasterizerDiscardEnable != VK_TRUE) &&
                    (pObjectCreateInfo->flags.sampleShadingEnable == false))
                {
                    const auto& palProperties = pDevice->VkPhysicalDevice(DefaultDeviceIndex)->PalProperties();
                    const auto& info          = pPalPipeline[deviceIdx]->GetInfo();

                    if ((info.ps.flags.perSampleShading == 1) ||
                        ((info.ps.flags.usesSampleMask  == 1) &&
                         (palProperties.gfxipProperties.flags.supportVrsWithDsExports == 0)))
                    {
                        // Override the shader rate to 1x1 if SampleId used in shader or
                        // supportVrsWithDsExports is not supported and SampleMask used in shader.
                        Force1x1ShaderRate(&pObjectCreateInfo->immedInfo.vrsRateParams);
                        pObjectCreateInfo->flags.force1x1ShaderRate = true;
                        pObjectCreateInfo->msaa.pixelShaderSamples  = pObjectCreateInfo->msaa.coverageSamples;
                    }
                }

                palResult = pRSCache->CreateMsaaState(
                    pObjectCreateInfo->msaa,
                    pAllocator,
                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT,
                    pPalMsaa);
            }

            // Create the PAL color blend state object
            if (palResult == Pal::Result::Success)
            {
                palResult = pRSCache->CreateColorBlendState(
                    pObjectCreateInfo->blend,
                    pAllocator,
                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT,
                    pPalColorBlend);
            }

            // Create the PAL depth stencil state object
            if ((palResult == Pal::Result::Success) && pObjectCreateInfo->flags.bindDepthStencilObject)
            {
                palResult = pRSCache->CreateDepthStencilState(
                    pObjectCreateInfo->immedInfo.depthStencilCreateInfo,
                    pAllocator,
                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT,
                    pPalDepthStencil);
            }

            // Reset the PAL stencil maskupdate flags
            pObjectCreateInfo->immedInfo.stencilRefMasks.flags.u8All = 0xff;
        }

        result = PalToVkResult(palResult);
    }

    PipelineBinaryInfo* pBinaryInfo = nullptr;

    if ((pDevice->IsExtensionEnabled(DeviceExtensions::AMD_SHADER_INFO) ||
        (pDevice->IsExtensionEnabled(DeviceExtensions::KHR_PIPELINE_EXECUTABLE_PROPERTIES) &&
        ((pCreateInfo->flags & VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR) != 0))) &&
        (result == VK_SUCCESS))
    {
        pBinaryInfo = PipelineBinaryInfo::Create(
            pPipelineBinarySizes[DefaultDeviceIndex],
            pPipelineBinaries[DefaultDeviceIndex],
            pAllocator);
    }

    // On success, wrap it up in a Vulkan object.
    if (result == VK_SUCCESS)
    {
        const bool viewIndexFromDeviceIndex = Util::TestAnyFlagSet(
            pCreateInfo->flags,
            VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT);

        PipelineInternalBufferInfo internalBuffer = *pInternalBuffer;
        if (pInternalBuffer->dataSize > 0)
        {
            internalBuffer.pData = Util::VoidPtrInc(pSystemMem, sizeof(GraphicsPipeline) + (palSize * numPalDevices));
            memcpy(internalBuffer.pData, pInternalBuffer->pData, pInternalBuffer->dataSize);
        }

        VK_PLACEMENT_NEW(pSystemMem) GraphicsPipeline(
            pDevice,
            pPalPipeline,
            pPipelineLayout,
            pObjectCreateInfo->immedInfo,
            pObjectCreateInfo->staticStateMask,
            pObjectCreateInfo->flags.bindDepthStencilObject,
            pObjectCreateInfo->flags.bindTriangleRasterState,
            pObjectCreateInfo->flags.bindStencilRefMasks,
            pObjectCreateInfo->flags.bindInputAssemblyState,
            pObjectCreateInfo->flags.force1x1ShaderRate,
            pObjectCreateInfo->flags.customSampleLocations,
            pObjectCreateInfo->flags.isPointSizeUsed,
#if VKI_RAY_TRACING
            pObjectCreateInfo->flags.hasRayTracing,
            pObjectCreateInfo->dispatchRaysUserDataOffset,
#endif
            *pVbInfo,
            &internalBuffer,
            pPalMsaa,
            pPalColorBlend,
            pPalDepthStencil,
            pObjectCreateInfo->sampleCoverage,
            viewIndexFromDeviceIndex,
            pBinaryInfo,
            apiPsoHash,
            &palPipelineHasher);

        *pPipeline = GraphicsPipeline::HandleFromVoidPointer(pSystemMem);
    }

    if (result != VK_SUCCESS)
    {
        pRSCache->DestroyMsaaState(pPalMsaa, pAllocator);
        pRSCache->DestroyColorBlendState(pPalColorBlend, pAllocator);

        if (pPalDepthStencil[0] != nullptr)
        {
            pRSCache->DestroyDepthStencilState(pPalDepthStencil, pAllocator);
        }

        // Something went wrong with creating the PAL object. Free memory and return error.
        for (uint32_t deviceIdx = 0; deviceIdx < pDevice->NumPalDevices(); deviceIdx++)
        {
            if (pPalPipeline[deviceIdx] != nullptr)
            {
                pPalPipeline[deviceIdx]->Destroy();
            }
        }

        if (pBinaryInfo != nullptr)
        {
            pBinaryInfo->Destroy(pAllocator);
        }

        pDevice->FreeApiObject(pAllocator, pSystemMem);
    }

    return result;
}

// =====================================================================================================================
// Create a graphics pipeline object.
VkResult GraphicsPipeline::Create(
    Device*                                 pDevice,
    PipelineCache*                          pPipelineCache,
    const VkGraphicsPipelineCreateInfo*     pCreateInfo,
    const VkAllocationCallbacks*            pAllocator,
    VkPipeline*                             pPipeline)
{
    uint64 startTimeTicks = Util::GetPerfCpuTime();

    PipelineCompiler* pDefaultCompiler = pDevice->GetCompiler(DefaultDeviceIndex);

    const VkPipelineCreationFeedbackCreateInfoEXT* pPipelineCreationFeedbackCreateInfo = nullptr;

    pDefaultCompiler->GetPipelineCreationFeedback(static_cast<const VkStructHeader*>(pCreateInfo->pNext),
                                                  &pPipelineCreationFeedbackCreateInfo);

    // 1. Get pipeline layout
    VK_ASSERT(pCreateInfo->layout != VK_NULL_HANDLE);
    PipelineLayout* pPipelineLayout = PipelineLayout::ObjectFromHandle(pCreateInfo->layout);

    // 2. Build pipeline binary create info
    GraphicsPipelineBinaryCreateInfo binaryCreateInfo  = {};
    GraphicsPipelineShaderStageInfo  shaderStageInfo   = {};
    VbBindingInfo                    vbInfo            = {};
    PipelineInternalBufferInfo       internalBufferInfo = {};
    ShaderModuleHandle               tempModules[ShaderStage::ShaderStageGfxCount] = {};

    VkResult result = BuildPipelineBinaryCreateInfo(
        pDevice,
        pCreateInfo,
        pPipelineLayout,
        pPipelineCache,
        &binaryCreateInfo,
        &shaderStageInfo,
        &vbInfo,
        &internalBufferInfo,
        tempModules);

    // 3. Create pipeine binaries
    size_t                pipelineBinarySizes[MaxPalDevices] = {};
    const void*           pPipelineBinaries[MaxPalDevices]   = {};
    Util::MetroHash::Hash cacheId[MaxPalDevices]             = {};

    if (result == VK_SUCCESS)
    {
        result = CreatePipelineBinaries(pDevice,
                                        pCreateInfo,
                                        &shaderStageInfo,
                                        pPipelineLayout,
                                        &binaryCreateInfo,
                                        pPipelineCache,
                                        pPipelineCreationFeedbackCreateInfo,
                                        cacheId,
                                        pipelineBinarySizes,
                                        pPipelineBinaries);
    }

    uint64_t pipelineHash = 0;
    GraphicsPipelineObjectCreateInfo objectCreateInfo = {};
    GraphicsPipelineBinaryInfo       binaryInfo       = {};
    if (result == VK_SUCCESS)
    {
        pipelineHash = Vkgc::IPipelineDumper::GetPipelineHash(&binaryCreateInfo.pipelineInfo);

        // 4. Build pipeline object create info
        binaryInfo.pOptimizerKey = &binaryCreateInfo.pipelineProfileKey;
#if VKI_RAY_TRACING
        binaryInfo.hasRayTracing = binaryCreateInfo.pipelineInfo.rtState.threadGroupSizeX > 0;
#endif
        binaryInfo.hasMesh       = binaryCreateInfo.pipelineInfo.mesh.pModuleData != nullptr;

        BuildPipelineObjectCreateInfo(
            pDevice, pCreateInfo, &vbInfo, &binaryInfo, pPipelineLayout, &objectCreateInfo);

        objectCreateInfo.immedInfo.checkDeferCompilePipeline =
            pDevice->GetRuntimeSettings().deferCompileOptimizedPipeline &&
            (binaryCreateInfo.pipelineInfo.enableEarlyCompile || binaryCreateInfo.pipelineInfo.enableUberFetchShader);

        objectCreateInfo.flags.isPointSizeUsed = binaryCreateInfo.pipelineMetadata.pointSizeUsed;

#if VKI_RAY_TRACING
        objectCreateInfo.dispatchRaysUserDataOffset = pPipelineLayout->GetDispatchRaysUserData();
#endif

        // 5. Create pipeline objects
        result = CreatePipelineObjects(
            pDevice,
            pCreateInfo,
            pAllocator,
            pPipelineLayout,
            &vbInfo,
            &internalBufferInfo,
            pipelineBinarySizes,
            pPipelineBinaries,
            pPipelineCache,
            cacheId,
            &objectCreateInfo,
            pPipeline);
    }

    // Free the temporary newly-built shader modules
    FreeTempModules(pDevice, ShaderStage::ShaderStageGfxCount, tempModules);

    if (internalBufferInfo.pData != nullptr)
    {
        pDevice->VkInstance()->FreeMem(internalBufferInfo.pData);
        internalBufferInfo.pData = nullptr;
    }
    // Free the created pipeline binaries now that the PAL Pipelines/PipelineBinaryInfo have read them.
    for (uint32_t deviceIdx = 0; deviceIdx < pDevice->NumPalDevices(); deviceIdx++)
    {
        if (pPipelineBinaries[deviceIdx] != nullptr)
        {
            pDevice->GetCompiler(deviceIdx)->FreeGraphicsPipelineBinary(
                &binaryCreateInfo, pPipelineBinaries[deviceIdx], pipelineBinarySizes[deviceIdx]);
        }
    }

    // Deferred compile will reuse all object generated in BuildPipelineBinaryCreateInfo.
    // i.e. we need keep temp buffer in binaryCreateInfo
    pDefaultCompiler->FreeGraphicsPipelineCreateInfo(&binaryCreateInfo,
                                                     objectCreateInfo.immedInfo.checkDeferCompilePipeline);

    if (objectCreateInfo.immedInfo.checkDeferCompilePipeline)
    {
        GraphicsPipeline* pThis = GraphicsPipeline::ObjectFromHandle(*pPipeline);
        result = pThis->BuildDeferCompileWorkload(pDevice,
                                                  pPipelineCache,
                                                  &binaryCreateInfo,
                                                  &shaderStageInfo,
                                                  &objectCreateInfo);
        if (result == VK_SUCCESS)
        {
            pDefaultCompiler->ExecuteDeferCompile(&pThis->m_deferWorkload);
        }
    }

    if (result == VK_SUCCESS)
    {
        uint64_t durationTicks = Util::GetPerfCpuTime() - startTimeTicks;
        uint64_t duration = vk::utils::TicksToNano(durationTicks);
        binaryCreateInfo.pipelineFeedback.feedbackValid = true;
        binaryCreateInfo.pipelineFeedback.duration = duration;
        pDefaultCompiler->SetPipelineCreationFeedbackInfo(
            pPipelineCreationFeedbackCreateInfo,
            pCreateInfo->stageCount,
            pCreateInfo->pStages,
            &binaryCreateInfo.pipelineFeedback,
            binaryCreateInfo.stageFeedback);

        // The hash is same as pipline dump file name, we can easily analyze further.
        AmdvlkLog(pDevice->GetRuntimeSettings().logTagIdMask,
                  PipelineCompileTime,
                  "0x%016llX-%llu",
                  pipelineHash, duration);
    }

    return result;
}

// =====================================================================================================================
static size_t GetVertexInputStructSize(
    const VkPipelineVertexInputStateCreateInfo* pVertexInput)
{
    size_t size = 0;
    size += sizeof(VkPipelineVertexInputStateCreateInfo);
    size += sizeof(VkVertexInputBindingDescription) * pVertexInput->vertexBindingDescriptionCount;
    size += sizeof(VkVertexInputAttributeDescription) * pVertexInput->vertexAttributeDescriptionCount;

    const VkPipelineVertexInputDivisorStateCreateInfoEXT* pVertexDivisor = nullptr;
    const vk::VkStructHeader* pStructHeader =
        static_cast<const vk::VkStructHeader*>(pVertexInput->pNext);
    while (pStructHeader != nullptr)
    {
        if (pStructHeader->sType == VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT)
        {
            pVertexDivisor = reinterpret_cast<const VkPipelineVertexInputDivisorStateCreateInfoEXT*>(pStructHeader);
            break;
        }
        else
        {
            pStructHeader = pStructHeader->pNext;
        }
    }

    if (pVertexDivisor != nullptr)
    {
        size += sizeof(VkPipelineVertexInputDivisorStateCreateInfoEXT);
        size += sizeof(VkVertexInputBindingDivisorDescriptionEXT) * pVertexDivisor->vertexBindingDivisorCount;
    }

    return size;
}

// =====================================================================================================================
static void CopyVertexInputStruct(
    const VkPipelineVertexInputStateCreateInfo* pSrcVertexInput,
    VkPipelineVertexInputStateCreateInfo*       pDestVertexInput)
{
    // Copy VkPipelineVertexInputStateCreateInfo
    *pDestVertexInput = *pSrcVertexInput;
    void* pNext = Util::VoidPtrInc(pDestVertexInput, sizeof(VkPipelineVertexInputStateCreateInfo));

    // Copy VkVertexInputBindingDescription
    pDestVertexInput->pVertexBindingDescriptions = reinterpret_cast<VkVertexInputBindingDescription*>(pNext);
    size_t size = sizeof(VkVertexInputBindingDescription) * pSrcVertexInput->vertexBindingDescriptionCount;
    memcpy(pNext, pSrcVertexInput->pVertexBindingDescriptions, size);
    pNext = Util::VoidPtrInc(pNext, size);

    // Copy VkVertexInputAttributeDescription
    pDestVertexInput->pVertexAttributeDescriptions = reinterpret_cast<VkVertexInputAttributeDescription*>(pNext);
    size = sizeof(VkVertexInputAttributeDescription) * pSrcVertexInput->vertexAttributeDescriptionCount;
    memcpy(pNext, pSrcVertexInput->pVertexAttributeDescriptions, size);
    pNext = Util::VoidPtrInc(pNext, size);

    const VkPipelineVertexInputDivisorStateCreateInfoEXT* pSrcVertexDivisor = nullptr;
    const vk::VkStructHeader* pStructHeader =
        reinterpret_cast<const vk::VkStructHeader*>(pSrcVertexInput->pNext);
    while (pStructHeader != nullptr)
    {
        if (pStructHeader->sType == VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT)
        {
            pSrcVertexDivisor = reinterpret_cast<const VkPipelineVertexInputDivisorStateCreateInfoEXT*>(pStructHeader);
            break;
        }
        else
        {
            pStructHeader = pStructHeader->pNext;
        }
    }

    if (pSrcVertexDivisor != nullptr)
    {
        // Copy VkPipelineVertexInputDivisorStateCreateInfoEXT
        VkPipelineVertexInputDivisorStateCreateInfoEXT* pDestVertexDivisor =
            reinterpret_cast<VkPipelineVertexInputDivisorStateCreateInfoEXT*>(pNext);
        *pDestVertexDivisor = *pSrcVertexDivisor;
        pDestVertexInput->pNext = pDestVertexDivisor;
        pNext = Util::VoidPtrInc(pNext, sizeof(VkPipelineVertexInputDivisorStateCreateInfoEXT));

        // Copy VkVertexInputBindingDivisorDescriptionEXT
        pDestVertexDivisor->pVertexBindingDivisors = reinterpret_cast<VkVertexInputBindingDivisorDescriptionEXT*>(pNext);
        size = sizeof(VkVertexInputBindingDivisorDescriptionEXT) * pSrcVertexDivisor->vertexBindingDivisorCount;
        memcpy(pNext, pSrcVertexDivisor->pVertexBindingDivisors, size);
        pNext = Util::VoidPtrInc(pNext, size);
    }
}

// =====================================================================================================================
VkResult GraphicsPipeline::BuildDeferCompileWorkload(
    Device*                           pDevice,
    PipelineCache*                    pPipelineCache,
    GraphicsPipelineBinaryCreateInfo* pBinaryCreateInfo,
    GraphicsPipelineShaderStageInfo*  pShaderStageInfo,
    GraphicsPipelineObjectCreateInfo* pObjectCreateInfo)
{
    VkResult result = VK_SUCCESS;
    DeferGraphicsPipelineCreateInfo* pCreateInfo = nullptr;

    // Calculate payload size
    size_t payloadSize = sizeof(DeferGraphicsPipelineCreateInfo) + sizeof(Util::Event);
    for (uint32_t i = 0; i < ShaderStage::ShaderStageGfxCount; i++)
    {
        if (pShaderStageInfo->stages[i].pEntryPoint != nullptr)
        {
            payloadSize += strlen(pShaderStageInfo->stages[i].pEntryPoint) + 1;
            if (pShaderStageInfo->stages[i].pSpecializationInfo != nullptr)
            {
                auto pSpecializationInfo = pShaderStageInfo->stages[i].pSpecializationInfo;
                payloadSize += sizeof(VkSpecializationInfo);
                payloadSize += sizeof(VkSpecializationMapEntry) * pSpecializationInfo->mapEntryCount;
                payloadSize += pSpecializationInfo->dataSize;
            }
        }
    }

    size_t vertexInputSize = 0;
    if ((pShaderStageInfo->stages[ShaderStage::ShaderStageVertex].pEntryPoint != nullptr) &&
        (pBinaryCreateInfo->pipelineInfo.pVertexInput != nullptr))
    {
        vertexInputSize =  GetVertexInputStructSize(pBinaryCreateInfo->pipelineInfo.pVertexInput);
        payloadSize += vertexInputSize;
    }

    size_t memOffset = 0;
    Instance* pInstance = pDevice->VkInstance();
    void* pPayloadMem = pInstance->AllocMem(payloadSize, VK_DEFAULT_MEM_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);

    if (pPayloadMem == nullptr)
    {
        result = VK_ERROR_OUT_OF_HOST_MEMORY;
    }

    if (result == VK_SUCCESS)
    {
        memset(pPayloadMem, 0, payloadSize);
        pCreateInfo = static_cast<DeferGraphicsPipelineCreateInfo*>(pPayloadMem);
        memOffset = sizeof(DeferGraphicsPipelineCreateInfo);

        // Fill create info and reset defer compile related options
        pCreateInfo->pDevice          = pDevice;
        pCreateInfo->pPipelineCache   = pPipelineCache;
        pCreateInfo->pPipeline        = this;
        pCreateInfo->shaderStageInfo  = *pShaderStageInfo;
        pCreateInfo->binaryCreateInfo = *pBinaryCreateInfo;
        pCreateInfo->objectCreateInfo = *pObjectCreateInfo;

        pCreateInfo->binaryCreateInfo.pipelineInfo.enableEarlyCompile = false;
        pCreateInfo->binaryCreateInfo.pipelineInfo.enableUberFetchShader = false;
        pCreateInfo->objectCreateInfo.immedInfo.checkDeferCompilePipeline = false;

        PipelineShaderInfo* pShaderInfo[] =
        {
            &pCreateInfo->binaryCreateInfo.pipelineInfo.task,
            &pCreateInfo->binaryCreateInfo.pipelineInfo.vs,
            &pCreateInfo->binaryCreateInfo.pipelineInfo.tcs,
            &pCreateInfo->binaryCreateInfo.pipelineInfo.tes,
            &pCreateInfo->binaryCreateInfo.pipelineInfo.gs,
            &pCreateInfo->binaryCreateInfo.pipelineInfo.mesh,
            &pCreateInfo->binaryCreateInfo.pipelineInfo.fs,
        };

        // Do deep copy for binaryCreateInfo members
        for (uint32_t i = 0; i < ShaderStage::ShaderStageGfxCount; i++)
        {
            if (pShaderStageInfo->stages[i].pEntryPoint != nullptr)
            {
                size_t size = strlen(pShaderStageInfo->stages[i].pEntryPoint) + 1;
                char* pEntryPoint = reinterpret_cast<char*>(Util::VoidPtrInc(pPayloadMem, memOffset));
                memcpy(pEntryPoint, pShaderStageInfo->stages[i].pEntryPoint, size);
                pCreateInfo->shaderStageInfo.stages[i].pEntryPoint = pEntryPoint;
                pShaderInfo[i]->pEntryTarget = pEntryPoint;
                memOffset += size;

                if (pShaderStageInfo->stages[i].pSpecializationInfo != nullptr)
                {
                    auto pSrcSpecInfo = pShaderStageInfo->stages[i].pSpecializationInfo;
                    auto pDestSpecInfo = reinterpret_cast<VkSpecializationInfo*>(Util::VoidPtrInc(pPayloadMem, memOffset));
                    *pDestSpecInfo = *pSrcSpecInfo;
                    memOffset += sizeof(VkSpecializationInfo);

                    pDestSpecInfo->pMapEntries = reinterpret_cast<VkSpecializationMapEntry*>(Util::VoidPtrInc(pPayloadMem, memOffset));
                    memcpy(const_cast<VkSpecializationMapEntry*>(pDestSpecInfo->pMapEntries),
                           pSrcSpecInfo->pMapEntries,
                           pSrcSpecInfo->mapEntryCount * sizeof(VkSpecializationMapEntry));
                    memOffset += pSrcSpecInfo->mapEntryCount * sizeof(VkSpecializationMapEntry);

                    pDestSpecInfo->pData = Util::VoidPtrInc(pPayloadMem, memOffset);
                    memcpy(const_cast<void*>(pDestSpecInfo->pData),
                           pSrcSpecInfo->pData,
                           pSrcSpecInfo->dataSize);
                    memOffset += pSrcSpecInfo->dataSize;
                    pCreateInfo->shaderStageInfo.stages[i].pSpecializationInfo = pDestSpecInfo;
                    pShaderInfo[i]->pSpecializationInfo = pDestSpecInfo;
                }
            }
        }

        if (vertexInputSize != 0)
        {
            VkPipelineVertexInputStateCreateInfo* pVertexInput =
                reinterpret_cast<VkPipelineVertexInputStateCreateInfo*>(Util::VoidPtrInc(pPayloadMem, memOffset));
            pCreateInfo->binaryCreateInfo.pipelineInfo.pVertexInput = pVertexInput;
            CopyVertexInputStruct(pBinaryCreateInfo->pipelineInfo.pVertexInput, pVertexInput);
            memOffset += vertexInputSize;
        }

        // Build defer workload
        m_deferWorkload.pPayloads = pPayloadMem;
        m_deferWorkload.pEvent = VK_PLACEMENT_NEW(Util::VoidPtrInc(pPayloadMem, memOffset))(Util::Event);
        memOffset += sizeof(Util::Event);
        VK_ASSERT(memOffset == payloadSize);

        EventCreateFlags  flags = {};
        flags.manualReset = true;
        m_deferWorkload.pEvent->Init(flags);
        m_deferWorkload.Execute = ExecuteDeferCreateOptimizedPipeline;
    }

    return result;
}

// =====================================================================================================================
void GraphicsPipeline::ExecuteDeferCreateOptimizedPipeline(
    void *pPayload)
{
    DeferGraphicsPipelineCreateInfo* pCreateInfo = static_cast<DeferGraphicsPipelineCreateInfo*>(pPayload);
    pCreateInfo->pPipeline->DeferCreateOptimizedPipeline(pCreateInfo->pDevice,
                                                         pCreateInfo->pPipelineCache,
                                                         &pCreateInfo->binaryCreateInfo,
                                                         &pCreateInfo->shaderStageInfo,
                                                         &pCreateInfo->objectCreateInfo);
}

// =====================================================================================================================
VkResult GraphicsPipeline::DeferCreateOptimizedPipeline(
    Device*                           pDevice,
    PipelineCache*                    pPipelineCache,
    GraphicsPipelineBinaryCreateInfo* pBinaryCreateInfo,
    GraphicsPipelineShaderStageInfo*  pShaderStageInfo,
    GraphicsPipelineObjectCreateInfo* pObjectCreateInfo)
{
    VkResult              result = VK_SUCCESS;
    size_t                pipelineBinarySizes[MaxPalDevices] = {};
    const void*           pPipelineBinaries[MaxPalDevices]   = {};
    Util::MetroHash::Hash cacheId[MaxPalDevices]             = {};
    Pal::IPipeline*       pPalPipeline[MaxPalDevices]        = {};

    Pal::Result           palResult                          = Pal::Result::Success;
    size_t palSize =
        pDevice->PalDevice(DefaultDeviceIndex)->GetGraphicsPipelineSize(pObjectCreateInfo->pipeline, &palResult);
    VK_ASSERT(palResult == Pal::Result::Success);

    uint32_t numPalDevices = pDevice->NumPalDevices();
    void* pSystemMem = pDevice->VkInstance()->AllocMem(
        palSize, VK_DEFAULT_MEM_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    if (pSystemMem == nullptr)
    {
        result = VK_ERROR_OUT_OF_HOST_MEMORY;
    }

    if (result == VK_SUCCESS)
    {
        result = CreatePipelineBinaries(pDevice,
                                        nullptr,
                                        pShaderStageInfo,
                                        nullptr,
                                        pBinaryCreateInfo,
                                        pPipelineCache,
                                        nullptr,
                                        cacheId,
                                        pipelineBinarySizes,
                                        pPipelineBinaries);
    }

    if (result == VK_SUCCESS)
    {
        result = CreatePalPipelineObjects(pDevice,
                                          pPipelineCache,
                                          pObjectCreateInfo,
                                          pipelineBinarySizes,
                                          pPipelineBinaries,
                                          cacheId,
                                          pSystemMem,
                                          pPalPipeline);
    }

    if (result == VK_SUCCESS)
    {
        VK_ASSERT(pSystemMem == pPalPipeline[0]);
        SetOptimizedPipeline(pPalPipeline);
    }

    pDevice->GetCompiler(DefaultDeviceIndex)->FreeGraphicsPipelineCreateInfo(pBinaryCreateInfo, false);

    for (uint32_t deviceIdx = 0; deviceIdx < pDevice->NumPalDevices(); deviceIdx++)
    {
        if (pPipelineBinaries[deviceIdx] != nullptr)
        {
            pDevice->GetCompiler(deviceIdx)->FreeGraphicsPipelineBinary(
                pBinaryCreateInfo, pPipelineBinaries[deviceIdx], pipelineBinarySizes[deviceIdx]);
        }
    }
    return result;
}

// =====================================================================================================================
void GraphicsPipeline::SetOptimizedPipeline(
    Pal::IPipeline* pPalPipeline[MaxPalDevices])
{
    const bool optimizedPipeline = true;
    Util::MetroHash::Hash hash = {};
    Util::MetroHash64 palPipelineHasher;
    palPipelineHasher.Update(PalPipelineHash());
    palPipelineHasher.Update(optimizedPipeline);
    palPipelineHasher.Finalize(hash.bytes);

    Util::MutexAuto pipelineSwitchLock(&m_pipelineSwitchLock);
    memcpy(m_pOptimizedPipeline, pPalPipeline, sizeof(m_pOptimizedPipeline));
    m_optimizedPipelineHash = hash.qwords[0];
}

// =====================================================================================================================
GraphicsPipeline::GraphicsPipeline(
    Device* const                          pDevice,
    Pal::IPipeline**                       pPalPipeline,
    const PipelineLayout*                  pLayout,
    const GraphicsPipelineObjectImmedInfo& immedInfo,
    uint64_t                               staticStateMask,
    bool                                   bindDepthStencilObject,
    bool                                   bindTriangleRasterState,
    bool                                   bindStencilRefMasks,
    bool                                   bindInputAssemblyState,
    bool                                   force1x1ShaderRate,
    bool                                   customSampleLocations,
    bool                                   isPointSizeUsed,
#if VKI_RAY_TRACING
    bool                                   hasRayTracing,
    uint32_t                               dispatchRaysUserDataOffset,
#endif
    const VbBindingInfo&                   vbInfo,
    const PipelineInternalBufferInfo*      pInternalBuffer,
    Pal::IMsaaState**                      pPalMsaa,
    Pal::IColorBlendState**                pPalColorBlend,
    Pal::IDepthStencilState**              pPalDepthStencil,
    uint32_t                               coverageSamples,
    bool                                   viewIndexFromDeviceIndex,
    PipelineBinaryInfo*                    pBinary,
    uint64_t                               apiHash,
    Util::MetroHash64*                     pPalPipelineHasher)
    :
    GraphicsPipelineCommon(
#if VKI_RAY_TRACING
        hasRayTracing,
#endif
        pDevice),
    m_info(immedInfo),
    m_vbInfo(vbInfo),
    m_internalBufferInfo(*pInternalBuffer),
    m_pOptimizedPipeline{},
    m_optimizedPipelineHash(0),
    m_deferWorkload{},
    m_flags()
{
    Pipeline::Init(
        pPalPipeline,
        pLayout,
        pBinary,
        staticStateMask,
#if VKI_RAY_TRACING
        dispatchRaysUserDataOffset,
#endif
        apiHash);

    memcpy(m_pPalMsaa,         pPalMsaa,         sizeof(pPalMsaa[0])         * pDevice->NumPalDevices());
    memcpy(m_pPalColorBlend,   pPalColorBlend,   sizeof(pPalColorBlend[0])   * pDevice->NumPalDevices());
    memcpy(m_pPalDepthStencil, pPalDepthStencil, sizeof(pPalDepthStencil[0]) * pDevice->NumPalDevices());

    m_flags.viewIndexFromDeviceIndex = viewIndexFromDeviceIndex;
    m_flags.bindDepthStencilObject   = bindDepthStencilObject;
    m_flags.bindTriangleRasterState  = bindTriangleRasterState;
    m_flags.bindStencilRefMasks      = bindStencilRefMasks;
    m_flags.bindInputAssemblyState   = bindInputAssemblyState;
    m_flags.customSampleLocations    = customSampleLocations;
    m_flags.force1x1ShaderRate       = force1x1ShaderRate;
    m_flags.isPointSizeUsed          = isPointSizeUsed;
    CreateStaticState();

    pPalPipelineHasher->Update(m_palPipelineHash);
    pPalPipelineHasher->Finalize(reinterpret_cast<uint8*>(&m_palPipelineHash));
}

// =====================================================================================================================
// Creates instances of static pipeline state.  Much of this information can be cached at the device-level to help speed
// up pipeline-bind operations.
void GraphicsPipeline::CreateStaticState()
{
    RenderStateCache* pCache = m_pDevice->GetRenderStateCache();
    auto* pStaticTokens      = &m_info.staticTokens;

    pStaticTokens->inputAssemblyState         = DynamicRenderStateToken;
    pStaticTokens->triangleRasterState        = DynamicRenderStateToken;
    pStaticTokens->pointLineRasterState       = DynamicRenderStateToken;
    pStaticTokens->depthBias                  = DynamicRenderStateToken;
    pStaticTokens->blendConst                 = DynamicRenderStateToken;
    pStaticTokens->depthBounds                = DynamicRenderStateToken;
    pStaticTokens->viewport                   = DynamicRenderStateToken;
    pStaticTokens->scissorRect                = DynamicRenderStateToken;
    pStaticTokens->lineStippleState           = DynamicRenderStateToken;

    pStaticTokens->fragmentShadingRate        = DynamicRenderStateToken;

    if (m_flags.bindInputAssemblyState)
    {
        pStaticTokens->inputAssemblyState = pCache->CreateInputAssemblyState(m_info.inputAssemblyState);
    }

    if (m_flags.bindTriangleRasterState)
    {
        pStaticTokens->triangleRasterState = pCache->CreateTriangleRasterState(m_info.triangleRasterState);
    }

    if (ContainsStaticState(DynamicStatesInternal::LineWidth))
    {
        pStaticTokens->pointLineRasterState = pCache->CreatePointLineRasterState(
            m_info.pointLineRasterParams);
    }

    if (ContainsStaticState(DynamicStatesInternal::DepthBias))
    {
        pStaticTokens->depthBias = pCache->CreateDepthBias(m_info.depthBiasParams);
    }

    if (ContainsStaticState(DynamicStatesInternal::BlendConstants))
    {
        pStaticTokens->blendConst = pCache->CreateBlendConst(m_info.blendConstParams);
    }

    if (ContainsStaticState(DynamicStatesInternal::DepthBounds))
    {
        pStaticTokens->depthBounds = pCache->CreateDepthBounds(m_info.depthBoundParams);
    }

    if (ContainsStaticState(DynamicStatesInternal::Viewport))
    {
        pStaticTokens->viewport = pCache->CreateViewport(m_info.viewportParams);
    }

    if (ContainsStaticState(DynamicStatesInternal::Scissor))
    {
        pStaticTokens->scissorRect = pCache->CreateScissorRect(m_info.scissorRectParams);
    }

    if (ContainsStaticState(DynamicStatesInternal::LineStippleExt))
    {
        pStaticTokens->lineStippleState = pCache->CreateLineStipple(m_info.lineStippleParams);
    }

    if (ContainsStaticState(DynamicStatesInternal::FragmentShadingRateStateKhr))
    {
        pStaticTokens->fragmentShadingRate =
            pCache->CreateFragmentShadingRate(m_info.vrsRateParams);
    }
}

// =====================================================================================================================
// Destroys static pipeline state.
void GraphicsPipeline::DestroyStaticState(
    const VkAllocationCallbacks* pAllocator)
{
    RenderStateCache* pCache = m_pDevice->GetRenderStateCache();

    pCache->DestroyMsaaState(m_pPalMsaa, pAllocator);
    pCache->DestroyColorBlendState(m_pPalColorBlend, pAllocator);

    if (m_pPalDepthStencil[0] != nullptr)
    {
        pCache->DestroyDepthStencilState(m_pPalDepthStencil, pAllocator);
    }

    if (m_flags.bindInputAssemblyState)
    {
        pCache->DestroyInputAssemblyState(m_info.inputAssemblyState,
                                          m_info.staticTokens.inputAssemblyState);
    }

    if (m_flags.bindTriangleRasterState)
    {
        pCache->DestroyTriangleRasterState(m_info.triangleRasterState,
                                           m_info.staticTokens.triangleRasterState);
    }

    pCache->DestroyPointLineRasterState(m_info.pointLineRasterParams,
                                        m_info.staticTokens.pointLineRasterState);

    pCache->DestroyDepthBias(m_info.depthBiasParams,
                             m_info.staticTokens.depthBias);

    pCache->DestroyBlendConst(m_info.blendConstParams,
                              m_info.staticTokens.blendConst);

    pCache->DestroyDepthBounds(m_info.depthBoundParams,
                               m_info.staticTokens.depthBounds);

    pCache->DestroyViewport(m_info.viewportParams,
                            m_info.staticTokens.viewport);

    pCache->DestroyScissorRect(m_info.scissorRectParams,
                               m_info.staticTokens.scissorRect);

    pCache->DestroyLineStipple(m_info.lineStippleParams,
                               m_info.staticTokens.lineStippleState);

    pCache->DestroyFragmentShadingRate(m_info.vrsRateParams,
                                       m_info.staticTokens.fragmentShadingRate);
}

// =====================================================================================================================
VkResult GraphicsPipeline::Destroy(
    Device*                      pDevice,
    const VkAllocationCallbacks* pAllocator)
{
    if (m_deferWorkload.pEvent != nullptr)
    {
        auto result = m_deferWorkload.pEvent->Wait(10);
        if (result == Util::Result::Success)
        {
            Util::Destructor(m_deferWorkload.pEvent);
            pDevice->VkInstance()->FreeMem(m_deferWorkload.pPayloads);
        }
        m_deferWorkload.pEvent = nullptr;
        m_deferWorkload.pPayloads = nullptr;
    }

    DestroyStaticState(pAllocator);

    if (m_pOptimizedPipeline[0] != nullptr)
    {
        void* pBaseMem = m_pOptimizedPipeline[0];
        for (uint32_t deviceIdx = 0;
            (deviceIdx < m_pDevice->NumPalDevices()) && (m_pPalPipeline[deviceIdx] != nullptr);
            deviceIdx++)
        {
            m_pOptimizedPipeline[deviceIdx]->Destroy();
            m_pOptimizedPipeline[deviceIdx] = nullptr;
        }
        pDevice->VkInstance()->FreeMem(pBaseMem);
    }

    return Pipeline::Destroy(pDevice, pAllocator);
}

// =====================================================================================================================
// Binds this graphics pipeline's state to the given command buffer (with passed in wavelimits)
void GraphicsPipeline::BindToCmdBuffer(
    CmdBuffer*                             pCmdBuffer,
    const Pal::DynamicGraphicsShaderInfos& graphicsShaderInfos
    ) const
{
    AllGpuRenderState* pRenderState = pCmdBuffer->RenderState();

    // Get this pipeline's static tokens
    const auto& newTokens = m_info.staticTokens;

    // Get the old static tokens.  Copy these by value because in MGPU cases we update the new token state in a loop.
    const auto oldTokens = pRenderState->staticTokens;

    // Program static pipeline state.

    // This code will attempt to skip programming state state based on redundant value checks.  These checks are often
    // represented as token compares, where the tokens are two perfect hashes of previously compiled pipelines' static
    // parameter values.
    // If VIEWPORT is static, VIEWPORT_COUNT must be static as well
    if (ContainsStaticState(DynamicStatesInternal::Viewport))
    {
        if (CmdBuffer::IsStaticStateDifferent(oldTokens.viewports, newTokens.viewport))
        {
            pCmdBuffer->SetAllViewports(m_info.viewportParams, newTokens.viewport);
        }
    }
    else if (ContainsStaticState(DynamicStatesInternal::ViewportCount))
    {
        utils::IterateMask deviceGroup(pCmdBuffer->GetDeviceMask());
        do
        {
            uint32* pViewportCount = &(pCmdBuffer->PerGpuState(deviceGroup.Index())->viewport.count);

            if (*pViewportCount != m_info.viewportParams.count)
            {
                *pViewportCount = m_info.viewportParams.count;
                pRenderState->dirtyGraphics.viewport = 1;
            }
        }
        while (deviceGroup.IterateNext());
    }

    // We can just check DefaultDeviceIndex as the value can't vary between GPUs.
    if (pCmdBuffer->PerGpuState(DefaultDeviceIndex)->viewport.depthRange != m_info.viewportParams.depthRange)
    {
        utils::IterateMask deviceGroup(pCmdBuffer->GetDeviceMask());
        do
        {
            pCmdBuffer->PerGpuState(deviceGroup.Index())->viewport.depthRange = m_info.viewportParams.depthRange;
        }
        while (deviceGroup.IterateNext());

        pRenderState->dirtyGraphics.viewport = 1;
    }

    if (ContainsStaticState(DynamicStatesInternal::Scissor))
    {
        if (CmdBuffer::IsStaticStateDifferent(oldTokens.scissorRect, newTokens.scissorRect))
        {
            pCmdBuffer->SetAllScissors(m_info.scissorRectParams, newTokens.scissorRect);
        }
    }
    else if (ContainsStaticState(DynamicStatesInternal::ScissorCount))
    {
        utils::IterateMask deviceGroup(pCmdBuffer->GetDeviceMask());
        do
        {
            uint32* pScissorCount = &(pCmdBuffer->PerGpuState(deviceGroup.Index())->scissor.count);

            if (*pScissorCount != m_info.scissorRectParams.count)
            {
                *pScissorCount = m_info.scissorRectParams.count;
                pRenderState->dirtyGraphics.scissor = 1;
            }
        }
        while (deviceGroup.IterateNext());
    }

    if (m_flags.bindDepthStencilObject == false)
    {
        Pal::DepthStencilStateCreateInfo* pDepthStencilCreateInfo = &(pRenderState->depthStencilCreateInfo);

        if (ContainsStaticState(DynamicStatesInternal::DepthTestEnableExt) &&
            (pDepthStencilCreateInfo->depthEnable != m_info.depthStencilCreateInfo.depthEnable))
        {
            pDepthStencilCreateInfo->depthEnable = m_info.depthStencilCreateInfo.depthEnable;

            pRenderState->dirtyGraphics.depthStencil = 1;
        }
        if (ContainsStaticState(DynamicStatesInternal::DepthWriteEnableExt) &&
            (pDepthStencilCreateInfo->depthWriteEnable != m_info.depthStencilCreateInfo.depthWriteEnable))
        {
            pDepthStencilCreateInfo->depthWriteEnable = m_info.depthStencilCreateInfo.depthWriteEnable;

            pRenderState->dirtyGraphics.depthStencil = 1;
        }
        if (ContainsStaticState(DynamicStatesInternal::DepthCompareOpExt) &&
            (pDepthStencilCreateInfo->depthFunc != m_info.depthStencilCreateInfo.depthFunc))
        {
            pDepthStencilCreateInfo->depthFunc = m_info.depthStencilCreateInfo.depthFunc;

            pRenderState->dirtyGraphics.depthStencil = 1;
        }
        if (ContainsStaticState(DynamicStatesInternal::DepthBoundsTestEnableExt) &&
            (pDepthStencilCreateInfo->depthBoundsEnable != m_info.depthStencilCreateInfo.depthBoundsEnable))
        {
            pDepthStencilCreateInfo->depthBoundsEnable = m_info.depthStencilCreateInfo.depthBoundsEnable;

            pRenderState->dirtyGraphics.depthStencil = 1;
        }
        if (ContainsStaticState(DynamicStatesInternal::StencilTestEnableExt) &&
            (pDepthStencilCreateInfo->stencilEnable != m_info.depthStencilCreateInfo.stencilEnable))
        {
            pDepthStencilCreateInfo->stencilEnable = m_info.depthStencilCreateInfo.stencilEnable;

            pRenderState->dirtyGraphics.depthStencil = 1;
        }
        if (ContainsStaticState(DynamicStatesInternal::StencilOpExt) &&
            ((pDepthStencilCreateInfo->front.stencilFailOp != m_info.depthStencilCreateInfo.front.stencilFailOp) ||
             (pDepthStencilCreateInfo->front.stencilPassOp != m_info.depthStencilCreateInfo.front.stencilPassOp) ||
             (pDepthStencilCreateInfo->front.stencilDepthFailOp !=
              m_info.depthStencilCreateInfo.front.stencilDepthFailOp) ||
             (pDepthStencilCreateInfo->front.stencilFunc != m_info.depthStencilCreateInfo.front.stencilFunc) ||
             (pDepthStencilCreateInfo->back.stencilFailOp != m_info.depthStencilCreateInfo.back.stencilFailOp) ||
             (pDepthStencilCreateInfo->back.stencilPassOp != m_info.depthStencilCreateInfo.back.stencilPassOp) ||
             (pDepthStencilCreateInfo->back.stencilDepthFailOp !=
              m_info.depthStencilCreateInfo.back.stencilDepthFailOp) ||
             (pDepthStencilCreateInfo->back.stencilFunc != m_info.depthStencilCreateInfo.back.stencilFunc)))
        {
            pDepthStencilCreateInfo->front = m_info.depthStencilCreateInfo.front;
            pDepthStencilCreateInfo->back  = m_info.depthStencilCreateInfo.back;

            pRenderState->dirtyGraphics.depthStencil = 1;
        }
    }
    else
    {
        // Update static state to cmdBuffer when it's static DS. It's necessary because
        // it will be used to tell if the value is changed next time.
        pRenderState->depthStencilCreateInfo = m_info.depthStencilCreateInfo;
    }

    if (m_flags.bindTriangleRasterState == false)
    {
        // Update the static states to renderState
        pRenderState->triangleRasterState.frontFillMode   = m_info.triangleRasterState.frontFillMode;
        pRenderState->triangleRasterState.backFillMode    = m_info.triangleRasterState.backFillMode;
        pRenderState->triangleRasterState.provokingVertex = m_info.triangleRasterState.provokingVertex;

        if (ContainsStaticState(DynamicStatesInternal::FrontFaceExt))
        {
            pRenderState->triangleRasterState.frontFace = m_info.triangleRasterState.frontFace;
        }

        if (ContainsStaticState(DynamicStatesInternal::CullModeExt))
        {
            pRenderState->triangleRasterState.cullMode = m_info.triangleRasterState.cullMode;
        }

        if (ContainsStaticState(DynamicStatesInternal::DepthBiasEnableExt))
        {
            pRenderState->triangleRasterState.flags.frontDepthBiasEnable =
                m_info.triangleRasterState.flags.frontDepthBiasEnable;
            pRenderState->triangleRasterState.flags.backDepthBiasEnable =
                m_info.triangleRasterState.flags.backDepthBiasEnable;
        }

        pRenderState->dirtyGraphics.rasterState = 1;
    }
    else
    {
        pRenderState->triangleRasterState = m_info.triangleRasterState;
    }

    Pal::StencilRefMaskParams prevStencilRefMasks = pRenderState->stencilRefMasks;

    if (m_flags.bindStencilRefMasks == false)
    {
        // Until we expose Stencil Op Value, we always inherit the PSO value, which is currently Default == 1
        pRenderState->stencilRefMasks.frontOpValue   = m_info.stencilRefMasks.frontOpValue;
        pRenderState->stencilRefMasks.backOpValue    = m_info.stencilRefMasks.backOpValue;

        // We don't have to use tokens for these since the combiner does a redundancy check on the full value
        if (ContainsStaticState(DynamicStatesInternal::StencilCompareMask))
        {
            pRenderState->stencilRefMasks.frontReadMask  = m_info.stencilRefMasks.frontReadMask;
            pRenderState->stencilRefMasks.backReadMask   = m_info.stencilRefMasks.backReadMask;
        }

        if (ContainsStaticState(DynamicStatesInternal::StencilWriteMask))
        {
            pRenderState->stencilRefMasks.frontWriteMask = m_info.stencilRefMasks.frontWriteMask;
            pRenderState->stencilRefMasks.backWriteMask  = m_info.stencilRefMasks.backWriteMask;
        }

        if (ContainsStaticState(DynamicStatesInternal::StencilReference))
        {
            pRenderState->stencilRefMasks.frontRef       = m_info.stencilRefMasks.frontRef;
            pRenderState->stencilRefMasks.backRef        = m_info.stencilRefMasks.backRef;
        }
    }
    else
    {
        pRenderState->stencilRefMasks = m_info.stencilRefMasks;
    }

    // Check whether the dirty bit should be set
    if (memcmp(&pRenderState->stencilRefMasks, &prevStencilRefMasks, sizeof(Pal::StencilRefMaskParams)) != 0)
    {
        pRenderState->dirtyGraphics.stencilRef = 1;
    }

    if (m_flags.bindInputAssemblyState == false)
    {
        // Update the static states to renderState
        if (ContainsStaticState(DynamicStatesInternal::PrimitiveRestartEnableExt))
        {
            pRenderState->inputAssemblyState.primitiveRestartEnable = m_info.inputAssemblyState.primitiveRestartEnable;
        }

        pRenderState->inputAssemblyState.primitiveRestartIndex = m_info.inputAssemblyState.primitiveRestartIndex;
        pRenderState->inputAssemblyState.patchControlPoints    = m_info.inputAssemblyState.patchControlPoints;

        if (ContainsStaticState(DynamicStatesInternal::PrimitiveTopologyExt))
        {
            pRenderState->inputAssemblyState.topology = m_info.inputAssemblyState.topology;
        }

        pRenderState->dirtyGraphics.inputAssembly = 1;
    }
    else
    {
        pRenderState->inputAssemblyState = m_info.inputAssemblyState;
    }

    const bool useOptimizedPipeline = UseOptimizedPipeline();
    const uint64_t oldHash = pRenderState->boundGraphicsPipelineHash;
    const uint64_t newHash = useOptimizedPipeline ? m_optimizedPipelineHash : PalPipelineHash();

    utils::IterateMask deviceGroup(pCmdBuffer->GetDeviceMask());
    do
    {
        const uint32_t deviceIdx = deviceGroup.Index();

        Pal::ICmdBuffer* pPalCmdBuf = pCmdBuffer->PalCmdBuffer(deviceIdx);

        if (pRenderState->pGraphicsPipeline != nullptr)
        {
            bool palPipelineBound = false;
            if ((oldHash != newHash)
                )
            {
                Pal::PipelineBindParams params = {};

                params.pipelineBindPoint = Pal::PipelineBindPoint::Graphics;
                params.pPipeline         = useOptimizedPipeline ? m_pOptimizedPipeline[deviceIdx] : m_pPalPipeline[deviceIdx];
                params.graphics          = graphicsShaderInfos;
                params.apiPsoHash        = m_apiHash;

                pPalCmdBuf->CmdBindPipeline(params);
                palPipelineBound         = true;
            }

            if ((palPipelineBound == false) &&
                ContainsStaticState(DynamicStatesInternal::ColorWriteEnableExt) &&
                pRenderState->lastColorWriteEnableDynamic)
            {
                // Color write enable requires an explicit write to CB_TARGET_MASK in cases where the Pal pipeline bind
                // is skipped due to matching Pal pipeline hash values and CB_TARGET_MASK has been altered by the
                // previous pipeline via color write enable.  Passing in a count of 0 resets the mask.
                pRenderState->colorWriteMaskParams.count = 0;
                pRenderState->dirtyGraphics.colorWriteEnable     = 1;
            }

            if ((palPipelineBound == false) && ContainsStaticState(DynamicStatesInternal::RasterizerDiscardEnableExt))
            {
                // Need to update static rasterizerDiscardEnable setting if the Pal pipeline bind is skipped
                pRenderState->rasterizerDiscardEnable       = m_info.rasterizerDiscardEnable;
                pRenderState->dirtyGraphics.rasterizerDiscardEnable = 1;
            }
            else if (ContainsDynamicState(DynamicStatesInternal::RasterizerDiscardEnableExt))
            {
                // Binding a pipeline overwrites the dynamic rasterizerDiscardEnable setting so need to force validation
                pRenderState->dirtyGraphics.rasterizerDiscardEnable = 1;
            }
        }
        else
        {
            Pal::PipelineBindParams params = {};

            params.pipelineBindPoint = Pal::PipelineBindPoint::Graphics;
            params.pPipeline         = useOptimizedPipeline ? m_pOptimizedPipeline[deviceIdx] : m_pPalPipeline[deviceIdx];
            params.graphics          = graphicsShaderInfos;
            params.apiPsoHash        = m_apiHash;

            pPalCmdBuf->CmdBindPipeline(params);
        }

        // Bind state objects that are always static; these are redundancy checked by the pointer in the command buffer.
        if (m_flags.bindDepthStencilObject)
        {
            pCmdBuffer->PalCmdBindDepthStencilState(pPalCmdBuf, deviceIdx, m_pPalDepthStencil[deviceIdx]);

            pRenderState->dirtyGraphics.depthStencil = 0;
        }

        pCmdBuffer->PalCmdBindColorBlendState(pPalCmdBuf, deviceIdx, m_pPalColorBlend[deviceIdx]);
        pCmdBuffer->PalCmdBindMsaaState(pPalCmdBuf, deviceIdx, m_pPalMsaa[deviceIdx]);

        // Write parameters that are marked static pipeline state.  Redundancy check these based on static tokens:
        // skip the write if the previously written static token matches.

        if (CmdBuffer::IsStaticStateDifferent(oldTokens.inputAssemblyState, newTokens.inputAssemblyState) &&
                m_flags.bindInputAssemblyState)
        {
            pPalCmdBuf->CmdSetInputAssemblyState(m_info.inputAssemblyState);

            pRenderState->staticTokens.inputAssemblyState = newTokens.inputAssemblyState;
            pRenderState->dirtyGraphics.inputAssembly             = 0;
        }

        if (CmdBuffer::IsStaticStateDifferent(oldTokens.triangleRasterState, newTokens.triangleRasterState) &&
                m_flags.bindTriangleRasterState)
        {
            pPalCmdBuf->CmdSetTriangleRasterState(m_info.triangleRasterState);

            pRenderState->staticTokens.triangleRasterState = newTokens.triangleRasterState;
            pRenderState->dirtyGraphics.rasterState                = 0;
        }

        if (ContainsStaticState(DynamicStatesInternal::LineWidth) &&
            CmdBuffer::IsStaticStateDifferent(oldTokens.pointLineRasterState, newTokens.pointLineRasterState))
        {
            pPalCmdBuf->CmdSetPointLineRasterState(m_info.pointLineRasterParams);
            pRenderState->staticTokens.pointLineRasterState = newTokens.pointLineRasterState;
        }

        if (ContainsStaticState(DynamicStatesInternal::LineStippleExt) &&
            CmdBuffer::IsStaticStateDifferent(oldTokens.lineStippleState, newTokens.lineStippleState))
        {
            pPalCmdBuf->CmdSetLineStippleState(m_info.lineStippleParams);
            pRenderState->staticTokens.lineStippleState = newTokens.lineStippleState;
        }

        if (ContainsStaticState(DynamicStatesInternal::DepthBias) &&
            CmdBuffer::IsStaticStateDifferent(oldTokens.depthBiasState, newTokens.depthBias))
        {
            pPalCmdBuf->CmdSetDepthBiasState(m_info.depthBiasParams);
            pRenderState->staticTokens.depthBiasState = newTokens.depthBias;
        }

        if (ContainsStaticState(DynamicStatesInternal::BlendConstants) &&
            CmdBuffer::IsStaticStateDifferent(oldTokens.blendConst, newTokens.blendConst))
        {
            pPalCmdBuf->CmdSetBlendConst(m_info.blendConstParams);
            pRenderState->staticTokens.blendConst = newTokens.blendConst;
        }

        if (ContainsStaticState(DynamicStatesInternal::DepthBounds) &&
            CmdBuffer::IsStaticStateDifferent(oldTokens.depthBounds, newTokens.depthBounds))
        {
            pPalCmdBuf->CmdSetDepthBounds(m_info.depthBoundParams);
            pRenderState->staticTokens.depthBounds = newTokens.depthBounds;
        }

        if (ContainsStaticState(DynamicStatesInternal::SampleLocationsExt) &&
            (memcmp(&pRenderState->samplePattern, &m_info.samplePattern, sizeof(SamplePattern)) != 0))
        {
            pCmdBuffer->PalCmdSetMsaaQuadSamplePattern(
                m_info.samplePattern.sampleCount, m_info.samplePattern.locations);
            pRenderState->samplePattern = m_info.samplePattern;
            pRenderState->dirtyGraphics.samplePattern = 0;
        }

        if (ContainsStaticState(DynamicStatesInternal::ColorWriteEnableExt))
        {
            if (pRenderState->lastColorWriteEnableDynamic)
            {
                 pRenderState->lastColorWriteEnableDynamic = false;
            }
            else
            {
                pRenderState->dirtyGraphics.colorWriteEnable = 0;
            }
        }

        // Only set the Fragment Shading Rate if the dynamic state is not set.
        if (ContainsStaticState(DynamicStatesInternal::FragmentShadingRateStateKhr) &&
            CmdBuffer::IsStaticStateDifferent(oldTokens.fragmentShadingRate, newTokens.fragmentShadingRate))
        {
            pPalCmdBuf->CmdSetPerDrawVrsRate(m_info.vrsRateParams);

            pRenderState->staticTokens.fragmentShadingRate = newTokens.fragmentShadingRate;
            pRenderState->dirtyGraphics.vrs = 0;
        }

        if ((useOptimizedPipeline == false) && (m_internalBufferInfo.dataSize > 0))
        {
            VK_ASSERT(m_internalBufferInfo.internalBufferCount > 0);
            Pal::gpusize gpuAddress = {};
            uint32_t* pCpuAddr = pPalCmdBuf->CmdAllocateEmbeddedData(m_internalBufferInfo.dataSize, 1, &gpuAddress);
            memcpy(pCpuAddr, m_internalBufferInfo.pData, m_internalBufferInfo.dataSize);
            for (uint32_t i = 0; i < m_internalBufferInfo.internalBufferCount; i++)
            {
                Pal::gpusize bufferAddress = gpuAddress;
                bufferAddress += m_internalBufferInfo.internalBufferEntries[i].bufferOffset;
                pPalCmdBuf->CmdSetUserData(Pal::PipelineBindPoint::Graphics,
                    m_internalBufferInfo.internalBufferEntries[i].userDataOffset,
                    2,
                    reinterpret_cast<uint32_t*>(&bufferAddress));
            }
        }
    }
    while (deviceGroup.IterateNext());

    pRenderState->boundGraphicsPipelineHash = newHash;

    // Binding GraphicsPipeline affects ViewMask,
    // because when VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT is specified
    // ViewMask for each VkPhysicalDevice is defined by DeviceIndex
    // not by current subpass during a render pass instance.
    const bool oldViewIndexFromDeviceIndex = pRenderState->viewIndexFromDeviceIndex;
    const bool newViewIndexFromDeviceIndex = ViewIndexFromDeviceIndex();

    if (oldViewIndexFromDeviceIndex != newViewIndexFromDeviceIndex)
    {
        // Update value of ViewIndexFromDeviceIndex for currently bound pipeline.
        pRenderState->viewIndexFromDeviceIndex = newViewIndexFromDeviceIndex;

        // Sync ViewMask state in CommandBuffer.
        pCmdBuffer->SetViewInstanceMask(pCmdBuffer->GetDeviceMask());
    }
}

// =====================================================================================================================
// Binds a null pipeline to PAL
void GraphicsPipeline::BindNullPipeline(CmdBuffer* pCmdBuffer)
{
    const uint32_t numDevices = pCmdBuffer->VkDevice()->NumPalDevices();

    Pal::PipelineBindParams params = {};
    params.pipelineBindPoint = Pal::PipelineBindPoint::Graphics;
    params.apiPsoHash = Pal::InternalApiPsoHash;

    for (uint32_t deviceIdx = 0; deviceIdx < numDevices; deviceIdx++)
    {
        Pal::ICmdBuffer* pPalCmdBuf = pCmdBuffer->PalCmdBuffer(deviceIdx);

        pPalCmdBuf->CmdBindPipeline(params);
        pPalCmdBuf->CmdBindMsaaState(nullptr);
        pPalCmdBuf->CmdBindColorBlendState(nullptr);
        pPalCmdBuf->CmdBindDepthStencilState(nullptr);
    }
}
} // namespace vk